mirror of
https://github.com/logto-io/logto.git
synced 2024-12-30 20:33:54 -05:00
feat(console,core): remove devFeature guard (#5366)
remove devFeature guard for IdP
This commit is contained in:
parent
6537b7a6b5
commit
c10d6b6884
17 changed files with 54 additions and 158 deletions
|
@ -2,7 +2,6 @@ import { useCallback, useMemo } from 'react';
|
|||
|
||||
import guides from '@/assets/docs/guides';
|
||||
import { type Guide } from '@/assets/docs/guides/types';
|
||||
import { isDevFeaturesEnabled } from '@/consts/env';
|
||||
import {
|
||||
thirdPartyAppCategory,
|
||||
type AppGuideCategory,
|
||||
|
@ -34,12 +33,7 @@ export const useAppGuideMetadata = (): {
|
|||
) => Record<AppGuideCategory, readonly Guide[]>;
|
||||
} => {
|
||||
const appGuides = useMemo(
|
||||
() =>
|
||||
guides.filter(
|
||||
({ metadata: { target, isThirdParty } }) =>
|
||||
// @simeng-li #FIXME: remove isDevFeaturesEnabled check once we have all guides ready
|
||||
target !== 'API' && (isDevFeaturesEnabled || !isThirdParty)
|
||||
),
|
||||
() => guides.filter(({ metadata: { target } }) => target !== 'API'),
|
||||
[]
|
||||
);
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ import {
|
|||
ApplicationDetailsTabs,
|
||||
EnterpriseSsoDetailsTabs,
|
||||
} from '@/consts';
|
||||
import { isCloud, isDevFeaturesEnabled } from '@/consts/env';
|
||||
import { isCloud } from '@/consts/env';
|
||||
import { TenantsContext } from '@/contexts/TenantsProvider';
|
||||
import OverlayScrollbar from '@/ds-components/OverlayScrollbar';
|
||||
import ApiResourceDetails from '@/pages/ApiResourceDetails';
|
||||
|
@ -82,12 +82,10 @@ function ConsoleContent() {
|
|||
<Route path="dashboard" element={<Dashboard />} />
|
||||
<Route path="applications">
|
||||
<Route index element={<Applications />} />
|
||||
{isDevFeaturesEnabled && (
|
||||
<Route
|
||||
path="third-party-applications"
|
||||
element={<Applications tab="thirdPartyApplications" />}
|
||||
/>
|
||||
)}
|
||||
<Route
|
||||
path="third-party-applications"
|
||||
element={<Applications tab="thirdPartyApplications" />}
|
||||
/>
|
||||
<Route path="create" element={<Applications />} />
|
||||
<Route path=":id/guide/:guideId" element={<ApplicationDetails />} />
|
||||
<Route path=":id">
|
||||
|
|
|
@ -11,7 +11,6 @@ import { Trans, useTranslation } from 'react-i18next';
|
|||
import CaretDown from '@/assets/icons/caret-down.svg';
|
||||
import CaretUp from '@/assets/icons/caret-up.svg';
|
||||
import FormCard from '@/components/FormCard';
|
||||
import { isDevFeaturesEnabled } from '@/consts/env';
|
||||
import { openIdProviderConfigPath } from '@/consts/oidc';
|
||||
import { AppDataContext } from '@/contexts/AppDataProvider';
|
||||
import Button from '@/ds-components/Button';
|
||||
|
@ -51,8 +50,8 @@ function EndpointsAndCredentials({ app: { type, secret, id, isThirdParty }, oidc
|
|||
targetBlank: true,
|
||||
}}
|
||||
>
|
||||
{/* Hide logto endpoint field in third-party application's form. @simeng-li FIXME: remove isDevFeatureEnabled flag */}
|
||||
{tenantEndpoint && (!isDevFeaturesEnabled || !isThirdParty) && (
|
||||
{/* Hide logto endpoint field in third-party application's form. */}
|
||||
{tenantEndpoint && !isThirdParty && (
|
||||
<FormField title="application_details.logto_endpoint">
|
||||
<CopyToClipboard
|
||||
isFullWidth
|
||||
|
|
|
@ -18,7 +18,6 @@ import DetailsPageHeader from '@/components/DetailsPage/DetailsPageHeader';
|
|||
import Drawer from '@/components/Drawer';
|
||||
import UnsavedChangesAlertModal from '@/components/UnsavedChangesAlertModal';
|
||||
import { ApplicationDetailsTabs } from '@/consts';
|
||||
import { isDevFeaturesEnabled } from '@/consts/env';
|
||||
import DeleteConfirmModal from '@/ds-components/DeleteConfirmModal';
|
||||
import TabNav, { TabNavItem } from '@/ds-components/TabNav';
|
||||
import TabWrapper from '@/ds-components/TabWrapper';
|
||||
|
@ -165,7 +164,7 @@ function ApplicationDetailsContent({ data, oidcConfig, onApplicationUpdated }: P
|
|||
</TabNavItem>
|
||||
</>
|
||||
)}
|
||||
{isDevFeaturesEnabled && data.isThirdParty && (
|
||||
{data.isThirdParty && (
|
||||
<>
|
||||
<TabNavItem href={`/applications/${data.id}/${ApplicationDetailsTabs.Permissions}`}>
|
||||
{t('application_details.permissions.name')}
|
||||
|
@ -218,7 +217,7 @@ function ApplicationDetailsContent({ data, oidcConfig, onApplicationUpdated }: P
|
|||
</TabWrapper>
|
||||
</>
|
||||
)}
|
||||
{isDevFeaturesEnabled && data.isThirdParty && (
|
||||
{data.isThirdParty && (
|
||||
<>
|
||||
<TabWrapper
|
||||
isActive={tab === ApplicationDetailsTabs.Permissions}
|
||||
|
|
|
@ -108,25 +108,21 @@ function GuideLibrary({ className, hasCardBorder, hasCardButton }: Props) {
|
|||
<div className={styles.checkboxGroupContainer}>
|
||||
<CheckboxGroup
|
||||
className={styles.checkboxGroup}
|
||||
options={allAppGuideCategories
|
||||
.filter(
|
||||
(category) => isDevFeaturesEnabled || category !== thirdPartyAppCategory
|
||||
)
|
||||
.map((category) => ({
|
||||
title: `guide.categories.${category}`,
|
||||
value: category,
|
||||
...cond(
|
||||
isCloud &&
|
||||
category === 'ThirdParty' && {
|
||||
tag: (
|
||||
<FeatureTag
|
||||
isVisible={currentPlan.quota.thirdPartyApplicationsLimit === 0}
|
||||
plan={ReservedPlanId.Pro}
|
||||
/>
|
||||
),
|
||||
}
|
||||
),
|
||||
}))}
|
||||
options={allAppGuideCategories.map((category) => ({
|
||||
title: `guide.categories.${category}`,
|
||||
value: category,
|
||||
...cond(
|
||||
isCloud &&
|
||||
category === 'ThirdParty' && {
|
||||
tag: (
|
||||
<FeatureTag
|
||||
isVisible={currentPlan.quota.thirdPartyApplicationsLimit === 0}
|
||||
plan={ReservedPlanId.Pro}
|
||||
/>
|
||||
),
|
||||
}
|
||||
),
|
||||
}))}
|
||||
value={filterCategories}
|
||||
onChange={(value) => {
|
||||
const sortedValue = allAppGuideCategories.filter((category) =>
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
import { type Application } from '@logto/schemas';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import useSWR from 'swr';
|
||||
|
||||
import { defaultPageSize } from '@/consts';
|
||||
import { type RequestError } from '@/hooks/use-api';
|
||||
import useSearchParametersWatcher from '@/hooks/use-search-parameters-watcher';
|
||||
import { buildUrl } from '@/utils/url';
|
||||
|
||||
const pageSize = defaultPageSize;
|
||||
const applicationsEndpoint = 'api/applications';
|
||||
|
||||
/**
|
||||
* This hook is the forked version of useApplicationsData. @see {@link (./use-application-data.ts)}
|
||||
* But have all the third party application related request and code removed.
|
||||
* This will be applied directly on the current application page.
|
||||
* To prevent the third party api request and code from being triggered.
|
||||
*
|
||||
* We use the isDevFeatureEnabled to determine if we should use this legacy hook or the new one.
|
||||
* This hook will be removed once we have the third-party application feature ready for production.
|
||||
*/
|
||||
const useLegacyApplicationsData = () => {
|
||||
const [{ page }, updateSearchParameters] = useSearchParametersWatcher({
|
||||
page: 1,
|
||||
});
|
||||
|
||||
const updatePagination = useCallback(
|
||||
(page: number) => {
|
||||
updateSearchParameters({ page });
|
||||
},
|
||||
[updateSearchParameters]
|
||||
);
|
||||
|
||||
const url = useMemo(
|
||||
() =>
|
||||
buildUrl(applicationsEndpoint, {
|
||||
page: String(page),
|
||||
page_size: String(pageSize),
|
||||
}),
|
||||
[page]
|
||||
);
|
||||
|
||||
const data = useSWR<[Application[], number], RequestError>(url);
|
||||
|
||||
return {
|
||||
...data,
|
||||
pagination: {
|
||||
page,
|
||||
pageSize,
|
||||
},
|
||||
paginationRecords: {
|
||||
firstPartyApplicationPage: page,
|
||||
thirdPartyApplicationPage: page,
|
||||
},
|
||||
showThirdPartyApplicationTab: false,
|
||||
updatePagination,
|
||||
};
|
||||
};
|
||||
|
||||
export default useLegacyApplicationsData;
|
|
@ -8,7 +8,7 @@ import ApplicationIcon from '@/components/ApplicationIcon';
|
|||
import ChargeNotification from '@/components/ChargeNotification';
|
||||
import ItemPreview from '@/components/ItemPreview';
|
||||
import PageMeta from '@/components/PageMeta';
|
||||
import { isDevFeaturesEnabled, isCloud } from '@/consts/env';
|
||||
import { isCloud } from '@/consts/env';
|
||||
import Button from '@/ds-components/Button';
|
||||
import CardTitle from '@/ds-components/CardTitle';
|
||||
import CopyToClipboard from '@/ds-components/CopyToClipboard';
|
||||
|
@ -23,7 +23,6 @@ import { buildUrl } from '@/utils/url';
|
|||
import GuideLibrary from './components/GuideLibrary';
|
||||
import GuideLibraryModal from './components/GuideLibraryModal';
|
||||
import useApplicationsData from './hooks/use-application-data';
|
||||
import useLegacyApplicationsData from './hooks/use-legacy-application-data';
|
||||
import * as styles from './index.module.scss';
|
||||
|
||||
const tabs = Object.freeze({
|
||||
|
@ -43,11 +42,6 @@ const buildTabPathWithPagePagination = (page: number, tab?: keyof typeof tabs) =
|
|||
return page > 1 ? buildUrl(pathname, { page: String(page) }) : pathname;
|
||||
};
|
||||
|
||||
// @simeng-li FIXME: Remove this when the third party applications is production ready
|
||||
const useApplicationDataHook = isDevFeaturesEnabled
|
||||
? useApplicationsData
|
||||
: useLegacyApplicationsData;
|
||||
|
||||
type Props = {
|
||||
tab?: keyof typeof tabs;
|
||||
};
|
||||
|
@ -68,7 +62,7 @@ function Applications({ tab }: Props) {
|
|||
updatePagination,
|
||||
paginationRecords,
|
||||
showThirdPartyApplicationTab,
|
||||
} = useApplicationDataHook(tab === 'thirdPartyApplications');
|
||||
} = useApplicationsData(tab === 'thirdPartyApplications');
|
||||
|
||||
const isLoading = !data && !error;
|
||||
const [applications, totalCount] = data ?? [];
|
||||
|
|
|
@ -4,7 +4,6 @@ import { type IRouterParamContext } from 'koa-router';
|
|||
import type Provider from 'oidc-provider';
|
||||
import { errors } from 'oidc-provider';
|
||||
|
||||
import { EnvSet } from '#src/env-set/index.js';
|
||||
import { consent } from '#src/libraries/session.js';
|
||||
import type Queries from '#src/tenants/Queries.js';
|
||||
import assertThat from '#src/utils/assert-that.js';
|
||||
|
@ -34,8 +33,7 @@ export default function koaAutoConsent<StateT, ContextT extends IRouterParamCont
|
|||
const application =
|
||||
clientId === demoAppApplicationId ? undefined : await findApplicationById(clientId);
|
||||
|
||||
// FIXME: @simeng-li remove this when the IdP is ready
|
||||
const shouldAutoConsent = !EnvSet.values.isDevFeaturesEnabled || !application?.isThirdParty;
|
||||
const shouldAutoConsent = !application?.isThirdParty;
|
||||
|
||||
if (shouldAutoConsent) {
|
||||
const redirectTo = await consent(ctx, provider, query, interactionDetails);
|
||||
|
|
|
@ -139,8 +139,7 @@ export default function postgresAdapter(
|
|||
new errors.InvalidClient(`invalid client ${id}`)
|
||||
);
|
||||
|
||||
// FIXME: @simeng-li Remove this check after the third-party feature is released
|
||||
if (EnvSet.values.isDevFeaturesEnabled && application.isThirdParty) {
|
||||
if (application.isThirdParty) {
|
||||
const clientScopes = await getThirdPartyClientScopes(applications, id);
|
||||
return transpileClient(application, clientScopes);
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ import dpopValidate from 'oidc-provider/lib/helpers/validate_dpop.js';
|
|||
import validatePresence from 'oidc-provider/lib/helpers/validate_presence.js';
|
||||
import instance from 'oidc-provider/lib/helpers/weak_cache.js';
|
||||
|
||||
import { EnvSet } from '#src/env-set/index.js';
|
||||
import { type EnvSet } from '#src/env-set/index.js';
|
||||
import type Queries from '#src/tenants/Queries.js';
|
||||
import assertThat from '#src/utils/assert-that.js';
|
||||
|
||||
|
@ -233,9 +233,7 @@ export const buildHandler: (
|
|||
}
|
||||
|
||||
// Check if the organization is granted (third-party application only) by the user
|
||||
// FIXME @simeng-li: remove the `isDevFeaturesEnabled` check when the feature is enabled
|
||||
if (
|
||||
EnvSet.values.isDevFeaturesEnabled &&
|
||||
(await isThirdPartyApplication(queries, client.clientId)) &&
|
||||
!(await isOrganizationConsentedToApplication(
|
||||
queries,
|
||||
|
|
|
@ -19,7 +19,7 @@ import koaBody from 'koa-body';
|
|||
import Provider, { errors } from 'oidc-provider';
|
||||
import snakecaseKeys from 'snakecase-keys';
|
||||
|
||||
import { EnvSet } from '#src/env-set/index.js';
|
||||
import { type EnvSet } from '#src/env-set/index.js';
|
||||
import RequestError from '#src/errors/RequestError/index.js';
|
||||
import { addOidcEventListeners } from '#src/event-listeners/index.js';
|
||||
import koaAuditLog from '#src/middleware/koa-audit-log.js';
|
||||
|
@ -129,13 +129,8 @@ export default function initOidc(envSet: EnvSet, queries: Queries, libraries: Li
|
|||
const scopes = await findResourceScopes(queries, libraries, ctx, indicator);
|
||||
const { client } = ctx.oidc;
|
||||
|
||||
// FIXME: @simeng-li Remove this check after the third-party client scope feature is released
|
||||
// Need to filter out the unsupported scopes for the third-party application.
|
||||
if (
|
||||
EnvSet.values.isDevFeaturesEnabled &&
|
||||
client &&
|
||||
(await isThirdPartyApplication(queries, client.clientId))
|
||||
) {
|
||||
if (client && (await isThirdPartyApplication(queries, client.clientId))) {
|
||||
const filteredScopes = await filterResourceScopesForTheThirdPartyApplication(
|
||||
libraries,
|
||||
client.clientId,
|
||||
|
|
|
@ -9,7 +9,6 @@ import { generateStandardId, generateStandardSecret } from '@logto/shared';
|
|||
import { conditional } from '@silverhand/essentials';
|
||||
import { boolean, object, string, z } from 'zod';
|
||||
|
||||
import { EnvSet } from '#src/env-set/index.js';
|
||||
import RequestError from '#src/errors/RequestError/index.js';
|
||||
import koaGuard from '#src/middleware/koa-guard.js';
|
||||
import koaPagination from '#src/middleware/koa-pagination.js';
|
||||
|
@ -28,6 +27,14 @@ import {
|
|||
const includesInternalAdminRole = (roles: Readonly<Array<{ role: Role }>>) =>
|
||||
roles.some(({ role: { name } }) => name === InternalRole.Admin);
|
||||
|
||||
const parseIsThirdPartQueryParam = (isThirdPartyQuery: 'true' | 'false' | undefined) => {
|
||||
if (isThirdPartyQuery === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
return isThirdPartyQuery === 'true';
|
||||
};
|
||||
|
||||
const applicationTypeGuard = z.nativeEnum(ApplicationType);
|
||||
|
||||
export default function applicationRoutes<T extends AuthedRouter>(
|
||||
|
@ -48,27 +55,16 @@ export default function applicationRoutes<T extends AuthedRouter>(
|
|||
countApplications,
|
||||
findApplications,
|
||||
} = queries.applications;
|
||||
|
||||
const {
|
||||
findApplicationsRolesByApplicationId,
|
||||
insertApplicationsRoles,
|
||||
deleteApplicationRole,
|
||||
findApplicationsRolesByRoleId,
|
||||
} = queries.applicationsRoles;
|
||||
|
||||
const { findRoleByRoleName } = queries.roles;
|
||||
|
||||
const parseIsThirdPartQueryParam = (isThirdPartyQuery: 'true' | 'false ' | undefined) => {
|
||||
// FIXME: @simeng-li Remove this guard once Logto as IdP is ready
|
||||
if (!EnvSet.values.isDevFeaturesEnabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isThirdPartyQuery === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
return isThirdPartyQuery === 'true';
|
||||
};
|
||||
|
||||
router.get(
|
||||
'/applications',
|
||||
koaPagination({ isOptional: true }),
|
||||
|
@ -83,12 +79,7 @@ export default function applicationRoutes<T extends AuthedRouter>(
|
|||
.or(applicationTypeGuard.transform((type) => [type]))
|
||||
.optional(),
|
||||
excludeRoleId: string().optional(),
|
||||
// FIXME: @simeng-li Remove this guard once Logto as IdP is ready
|
||||
...conditional(
|
||||
EnvSet.values.isDevFeaturesEnabled && {
|
||||
isThirdParty: z.union([z.literal('true'), z.literal('false')]).optional(),
|
||||
}
|
||||
),
|
||||
isThirdParty: z.union([z.literal('true'), z.literal('false')]).optional(),
|
||||
}),
|
||||
response: z.array(applicationResponseGuard),
|
||||
status: 200,
|
||||
|
@ -98,7 +89,6 @@ export default function applicationRoutes<T extends AuthedRouter>(
|
|||
const { searchParams } = ctx.URL;
|
||||
const { types, excludeRoleId, isThirdParty: isThirdPartyParam } = ctx.guard.query;
|
||||
|
||||
// @ts-expect-error FIXME: unknown type will be fixed once we have the isDevFeaturesEnabled guard removed
|
||||
const isThirdParty = parseIsThirdPartQueryParam(isThirdPartyParam);
|
||||
|
||||
// This will only parse the `search` query param, other params will be ignored. Please use query guard to validate them.
|
||||
|
|
|
@ -14,14 +14,13 @@ enum OriginalApplicationType {
|
|||
MachineToMachine = 'MachineToMachine',
|
||||
}
|
||||
|
||||
// FIXME: @simeng-li Remove this guard once Logto as IdP is ready
|
||||
// FIXME: @wangsijie Remove this guard once protected app is ready
|
||||
// @ts-expect-error -- hide the dev feature field from the guard type, but always return the full type to make the api logic simpler
|
||||
export const applicationResponseGuard: typeof Applications.guard = EnvSet.values
|
||||
.isDevFeaturesEnabled
|
||||
? Applications.guard
|
||||
: Applications.guard
|
||||
.omit({ isThirdParty: true, type: true, protectedAppMetadata: true })
|
||||
.omit({ type: true, protectedAppMetadata: true })
|
||||
.extend({ type: z.nativeEnum(OriginalApplicationType) });
|
||||
|
||||
const applicationCreateGuardWithProtectedAppMetadata = originalApplicationCreateGuard
|
||||
|
@ -65,7 +64,7 @@ export const applicationCreateGuard: typeof applicationCreateGuardWithProtectedA
|
|||
.values.isDevFeaturesEnabled
|
||||
? applicationCreateGuardWithProtectedAppMetadata
|
||||
: applicationCreateGuardWithProtectedAppMetadata
|
||||
.omit({ isThirdParty: true, type: true, protectedAppMetadata: true })
|
||||
.omit({ type: true, protectedAppMetadata: true })
|
||||
.extend({ type: z.nativeEnum(OriginalApplicationType) });
|
||||
|
||||
// FIXME: @wangsijie Remove this guard once protected app is ready
|
||||
|
|
|
@ -51,10 +51,13 @@ const createRouters = (tenant: TenantContext) => {
|
|||
applicationRoutes(managementRouter, tenant);
|
||||
applicationRoleRoutes(managementRouter, tenant);
|
||||
|
||||
// Third-party application related routes
|
||||
applicationUserConsentScopeRoutes(managementRouter, tenant);
|
||||
applicationSignInExperienceRoutes(managementRouter, tenant);
|
||||
applicationUserConsentOrganizationRoutes(managementRouter, tenant);
|
||||
|
||||
// FIXME: @wangsijie: remove this after the feature is enabled by default
|
||||
if (EnvSet.values.isDevFeaturesEnabled) {
|
||||
applicationUserConsentScopeRoutes(managementRouter, tenant);
|
||||
applicationSignInExperienceRoutes(managementRouter, tenant);
|
||||
applicationUserConsentOrganizationRoutes(managementRouter, tenant);
|
||||
applicationProtectedAppMetadataRoutes(managementRouter, tenant);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@ import { type IRouterParamContext } from 'koa-router';
|
|||
import { errors } from 'oidc-provider';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { EnvSet } from '#src/env-set/index.js';
|
||||
import { consent, getMissingScopes } from '#src/libraries/session.js';
|
||||
import koaGuard from '#src/middleware/koa-guard.js';
|
||||
import type Queries from '#src/tenants/Queries.js';
|
||||
|
@ -125,10 +124,8 @@ export default function consentRoutes<T extends IRouterParamContext>(
|
|||
},
|
||||
} = ctx;
|
||||
|
||||
// FIXME: @simeng-li remove this when the IdP is ready
|
||||
|
||||
// Grant the organizations to the application if the user has selected the organizations
|
||||
if (organizationIds?.length && EnvSet.values.isDevFeaturesEnabled) {
|
||||
if (organizationIds?.length) {
|
||||
const {
|
||||
session,
|
||||
params: { client_id: applicationId },
|
||||
|
@ -163,11 +160,6 @@ export default function consentRoutes<T extends IRouterParamContext>(
|
|||
}
|
||||
);
|
||||
|
||||
// FIXME: @simeng-li remove this when the IdP is ready
|
||||
if (!EnvSet.values.isDevFeaturesEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the consent info for the experience consent page.
|
||||
*/
|
||||
|
|
|
@ -240,6 +240,7 @@ export default function organizationRoutes<T extends AuthedRouter>(...args: Rout
|
|||
organizationRoleRoutes(...args);
|
||||
organizationScopeRoutes(...args);
|
||||
|
||||
// FIXME: @gao-sun
|
||||
if (EnvSet.values.isDevFeaturesEnabled) {
|
||||
organizationInvitationRoutes(...args);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ export default function systemRoutes<T extends AuthedRouter>(
|
|||
},
|
||||
]: RouterInitArgs<T>
|
||||
) {
|
||||
// FIXME: @wangsijie
|
||||
if (EnvSet.values.isDevFeaturesEnabled) {
|
||||
router.get(
|
||||
'/systems/application',
|
||||
|
|
Loading…
Reference in a new issue