1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-09-28 17:55:15 +02:00

Merge branch 'main' into melinda/terraform-provider-docs

This commit is contained in:
melindafekete 2024-10-30 14:06:28 +01:00
commit 83faf8bce5
No known key found for this signature in database
64 changed files with 5183 additions and 5049 deletions

2
.gitignore vendored
View File

@ -58,7 +58,7 @@ frontend/src/openapi/apis
frontend/src/openapi/index.ts frontend/src/openapi/index.ts
# Generated docs # Generated docs
website/docs/reference/api/**/sidebar.js website/docs/reference/api/**/sidebar.ts
website/docs/reference/api/**/**.info.mdx website/docs/reference/api/**/**.info.mdx
website/docs/generated website/docs/generated
reports/jest-junit.xml reports/jest-junit.xml

View File

@ -93,7 +93,7 @@
"lodash.mapvalues": "^4.6.0", "lodash.mapvalues": "^4.6.0",
"lodash.omit": "4.5.0", "lodash.omit": "4.5.0",
"millify": "^6.0.0", "millify": "^6.0.0",
"msw": "2.4.12", "msw": "2.5.0",
"orval": "^6.31.0", "orval": "^6.31.0",
"pkginfo": "0.4.1", "pkginfo": "0.4.1",
"plausible-tracker": "0.3.9", "plausible-tracker": "0.3.9",
@ -118,7 +118,7 @@
"typescript": "5.4.5", "typescript": "5.4.5",
"use-query-params": "^2.2.1", "use-query-params": "^2.2.1",
"vanilla-jsoneditor": "^0.23.0", "vanilla-jsoneditor": "^0.23.0",
"vite": "5.4.9", "vite": "5.4.10",
"vite-plugin-env-compatible": "2.0.1", "vite-plugin-env-compatible": "2.0.1",
"vite-plugin-svgr": "3.3.0", "vite-plugin-svgr": "3.3.0",
"vite-tsconfig-paths": "4.3.2", "vite-tsconfig-paths": "4.3.2",
@ -128,9 +128,9 @@
"resolutions": { "resolutions": {
"@codemirror/state": "6.4.1", "@codemirror/state": "6.4.1",
"@xmldom/xmldom": "^0.9.0", "@xmldom/xmldom": "^0.9.0",
"jsonpath-plus": "10.0.0", "jsonpath-plus": "10.1.0",
"json5": "^2.2.2", "json5": "^2.2.2",
"vite": "5.4.9", "vite": "5.4.10",
"semver": "7.6.3", "semver": "7.6.3",
"ws": "^8.18.0", "ws": "^8.18.0",
"@types/react": "18.3.11" "@types/react": "18.3.11"

View File

@ -11,7 +11,7 @@ interface IArchivedFeatureDeleteConfirmProps {
deletedFeatures: string[]; deletedFeatures: string[];
projectId: string; projectId: string;
open: boolean; open: boolean;
setOpen: React.Dispatch<React.SetStateAction<boolean>>; setOpen: (open: boolean) => void;
refetch: () => void; refetch: () => void;
} }

View File

@ -1,5 +1,4 @@
import { Alert, styled } from '@mui/material'; import { Alert, styled } from '@mui/material';
import type React from 'react';
import { Dialogue } from 'component/common/Dialogue/Dialogue'; import { Dialogue } from 'component/common/Dialogue/Dialogue';
import { formatUnknownError } from 'utils/formatUnknownError'; import { formatUnknownError } from 'utils/formatUnknownError';
import useToast from 'hooks/useToast'; import useToast from 'hooks/useToast';
@ -11,7 +10,7 @@ interface IArchivedFeatureReviveConfirmProps {
revivedFeatures: string[]; revivedFeatures: string[];
projectId: string; projectId: string;
open: boolean; open: boolean;
setOpen: React.Dispatch<React.SetStateAction<boolean>>; setOpen: (open: boolean) => void;
refetch: () => void; refetch: () => void;
} }

View File

@ -3,7 +3,6 @@ import { ConditionallyRender } from 'component/common/ConditionallyRender/Condit
import { EventTimeline } from 'component/events/EventTimeline/EventTimeline'; import { EventTimeline } from 'component/events/EventTimeline/EventTimeline';
import { useEventTimelineContext } from 'component/events/EventTimeline/EventTimelineContext'; import { useEventTimelineContext } from 'component/events/EventTimeline/EventTimelineContext';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { useUiFlag } from 'hooks/useUiFlag';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
const StyledEventTimelineSlider = styled(Box)(({ theme }) => ({ const StyledEventTimelineSlider = styled(Box)(({ theme }) => ({
@ -21,10 +20,9 @@ const StyledEventTimelineWrapper = styled(Box)(({ theme }) => ({
export const MainLayoutEventTimeline = () => { export const MainLayoutEventTimeline = () => {
const { isOss } = useUiConfig(); const { isOss } = useUiConfig();
const { open: showTimeline } = useEventTimelineContext(); const { open: showTimeline } = useEventTimelineContext();
const eventTimelineEnabled = useUiFlag('eventTimeline') && !isOss();
const [isInitialLoad, setIsInitialLoad] = useState(true); const [isInitialLoad, setIsInitialLoad] = useState(true);
const open = showTimeline && eventTimelineEnabled; const open = showTimeline && !isOss();
useEffect(() => { useEffect(() => {
setIsInitialLoad(false); setIsInitialLoad(false);

View File

@ -104,7 +104,6 @@ export const NewInUnleash = ({
); );
const { isOss, isEnterprise } = useUiConfig(); const { isOss, isEnterprise } = useUiConfig();
const signalsEnabled = useUiFlag('signals'); const signalsEnabled = useUiFlag('signals');
const eventTimelineEnabled = useUiFlag('eventTimeline');
const { setHighlighted } = useEventTimelineContext(); const { setHighlighted } = useEventTimelineContext();
@ -159,7 +158,7 @@ export const NewInUnleash = ({
}, },
docsLink: docsLink:
'https://docs.getunleash.io/reference/events#event-timeline', 'https://docs.getunleash.io/reference/events#event-timeline',
show: !isOss() && eventTimelineEnabled, show: !isOss(),
longDescription: ( longDescription: (
<> <>
<p> <p>
@ -174,7 +173,6 @@ export const NewInUnleash = ({
</p> </p>
</> </>
), ),
beta: true,
}, },
]; ];

View File

@ -3,7 +3,6 @@ import LinearScaleIcon from '@mui/icons-material/LinearScale';
import { useEventTimelineContext } from 'component/events/EventTimeline/EventTimelineContext'; import { useEventTimelineContext } from 'component/events/EventTimeline/EventTimelineContext';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { usePlausibleTracker } from 'hooks/usePlausibleTracker'; import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
import { useUiFlag } from 'hooks/useUiFlag';
const StyledHeaderEventTimelineButton = styled(IconButton, { const StyledHeaderEventTimelineButton = styled(IconButton, {
shouldForwardProp: (prop) => prop !== 'highlighted', shouldForwardProp: (prop) => prop !== 'highlighted',
@ -34,14 +33,13 @@ const StyledHeaderEventTimelineButton = styled(IconButton, {
export const HeaderEventTimelineButton = () => { export const HeaderEventTimelineButton = () => {
const { trackEvent } = usePlausibleTracker(); const { trackEvent } = usePlausibleTracker();
const { isOss } = useUiConfig(); const { isOss } = useUiConfig();
const eventTimeline = useUiFlag('eventTimeline') && !isOss();
const { const {
open: showTimeline, open: showTimeline,
setOpen: setShowTimeline, setOpen: setShowTimeline,
highlighted, highlighted,
} = useEventTimelineContext(); } = useEventTimelineContext();
if (!eventTimeline) return null; if (isOss()) return null;
return ( return (
<Tooltip <Tooltip

View File

@ -105,9 +105,9 @@ export const PersonalDashboard = () => {
const { trackEvent } = usePlausibleTracker(); const { trackEvent } = usePlausibleTracker();
const { setSplashSeen } = useSplashApi(); const { setSplashSeen } = useSplashApi();
const { splash } = useAuthSplash(); const { splash } = useAuthSplash();
const name = user?.name; const name = user?.name || '';
usePageTitle(`Dashboard: ${name}`); usePageTitle(name ? `Dashboard: ${name}` : 'Dashboard');
const { personalDashboard, refetch: refetchDashboard } = const { personalDashboard, refetch: refetchDashboard } =
usePersonalDashboard(); usePersonalDashboard();

View File

@ -47,6 +47,8 @@ import { ProjectOnboarding } from '../../../onboarding/flow/ProjectOnboarding';
import { useLocalStorageState } from 'hooks/useLocalStorageState'; import { useLocalStorageState } from 'hooks/useLocalStorageState';
import { ProjectOnboarded } from 'component/onboarding/flow/ProjectOnboarded'; import { ProjectOnboarded } from 'component/onboarding/flow/ProjectOnboarded';
import { usePlausibleTracker } from 'hooks/usePlausibleTracker'; import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
import { ArchivedFeatureActionCell } from '../../../archive/ArchiveTable/ArchivedFeatureActionCell/ArchivedFeatureActionCell';
import { ArchiveBatchActions } from '../../../archive/ArchiveTable/ArchiveBatchActions';
interface IPaginatedProjectFeatureTogglesProps { interface IPaginatedProjectFeatureTogglesProps {
environments: string[]; environments: string[];
@ -115,6 +117,8 @@ export const ProjectFeatureToggles = ({
setFeatureArchiveState, setFeatureArchiveState,
setFeatureStaleDialogState, setFeatureStaleDialogState,
setShowMarkCompletedDialogue, setShowMarkCompletedDialogue,
setShowFeatureReviveDialogue,
setShowFeatureDeleteDialogue,
} = useRowActions(refetch, projectId); } = useRowActions(refetch, projectId);
const isPlaceholder = Boolean(initialLoad || (loading && total)); const isPlaceholder = Boolean(initialLoad || (loading && total));
@ -321,7 +325,24 @@ export const ProjectFeatureToggles = ({
columnHelper.display({ columnHelper.display({
id: 'actions', id: 'actions',
header: '', header: '',
cell: ({ row }) => ( cell: ({ row }) =>
tableState.archived ? (
<ArchivedFeatureActionCell
project={projectId}
onRevive={() => {
setShowFeatureReviveDialogue({
featureId: row.id,
open: true,
});
}}
onDelete={() => {
setShowFeatureDeleteDialogue({
featureId: row.id,
open: true,
});
}}
/>
) : (
<ActionsCell <ActionsCell
row={row} row={row}
projectId={projectId} projectId={projectId}
@ -329,6 +350,7 @@ export const ProjectFeatureToggles = ({
onOpenStaleDialog={setFeatureStaleDialogState} onOpenStaleDialog={setFeatureStaleDialogState}
/> />
), ),
enableSorting: false, enableSorting: false,
enableHiding: false, enableHiding: false,
meta: { meta: {
@ -585,6 +607,16 @@ export const ProjectFeatureToggles = ({
} }
/> />
<BatchSelectionActionsBar count={selectedData.length}> <BatchSelectionActionsBar count={selectedData.length}>
{tableState.archived ? (
<ArchiveBatchActions
selectedIds={Object.keys(rowSelection)}
projectId={projectId}
onConfirm={() => {
refetch();
table.resetRowSelection();
}}
/>
) : (
<ProjectFeaturesBatchActions <ProjectFeaturesBatchActions
selectedIds={Object.keys(rowSelection)} selectedIds={Object.keys(rowSelection)}
data={selectedData} data={selectedData}
@ -592,6 +624,7 @@ export const ProjectFeatureToggles = ({
onResetSelection={table.resetRowSelection} onResetSelection={table.resetRowSelection}
onChange={refetch} onChange={refetch}
/> />
)}
</BatchSelectionActionsBar> </BatchSelectionActionsBar>
</Container> </Container>
); );

View File

@ -6,6 +6,7 @@ import {
type IFilterItem, type IFilterItem,
} from 'component/filter/Filters/Filters'; } from 'component/filter/Filters/Filters';
import { useProjectFlagCreators } from 'hooks/api/getters/useProjectFlagCreators/useProjectFlagCreators'; import { useProjectFlagCreators } from 'hooks/api/getters/useProjectFlagCreators/useProjectFlagCreators';
import { useUiFlag } from 'hooks/useUiFlag';
interface IProjectOverviewFilters { interface IProjectOverviewFilters {
state: FilterItemParamHolder; state: FilterItemParamHolder;
@ -21,6 +22,7 @@ export const ProjectOverviewFilters: VFC<IProjectOverviewFilters> = ({
const { tags } = useAllTags(); const { tags } = useAllTags();
const { flagCreators } = useProjectFlagCreators(project); const { flagCreators } = useProjectFlagCreators(project);
const [availableFilters, setAvailableFilters] = useState<IFilterItem[]>([]); const [availableFilters, setAvailableFilters] = useState<IFilterItem[]>([]);
const simplifyProjectOverview = useUiFlag('simplifyProjectOverview');
useEffect(() => { useEffect(() => {
const tagsOptions = (tags || []).map((tag) => ({ const tagsOptions = (tags || []).map((tag) => ({
@ -95,6 +97,18 @@ export const ProjectOverviewFilters: VFC<IProjectOverviewFilters> = ({
singularOperators: ['IS', 'IS_NOT'], singularOperators: ['IS', 'IS_NOT'],
pluralOperators: ['IS_ANY_OF', 'IS_NONE_OF'], pluralOperators: ['IS_ANY_OF', 'IS_NONE_OF'],
}, },
...(simplifyProjectOverview
? ([
{
label: 'Show only archived',
icon: 'inventory',
options: [{ label: 'True', value: 'true' }],
filterKey: 'archived',
singularOperators: ['IS'],
pluralOperators: ['IS_ANY_OF'],
},
] as IFilterItem[])
: []),
]; ];
setAvailableFilters(availableFilters); setAvailableFilters(availableFilters);

View File

@ -2,6 +2,8 @@ import { useState } from 'react';
import { FeatureArchiveDialog } from 'component/common/FeatureArchiveDialog/FeatureArchiveDialog'; import { FeatureArchiveDialog } from 'component/common/FeatureArchiveDialog/FeatureArchiveDialog';
import { FeatureStaleDialog } from 'component/common/FeatureStaleDialog/FeatureStaleDialog'; import { FeatureStaleDialog } from 'component/common/FeatureStaleDialog/FeatureStaleDialog';
import { MarkCompletedDialogue } from 'component/feature/FeatureView/FeatureOverview/FeatureLifecycle/MarkCompletedDialogue'; import { MarkCompletedDialogue } from 'component/feature/FeatureView/FeatureOverview/FeatureLifecycle/MarkCompletedDialogue';
import { ArchivedFeatureDeleteConfirm } from '../../../../archive/ArchiveTable/ArchivedFeatureActionCell/ArchivedFeatureDeleteConfirm/ArchivedFeatureDeleteConfirm';
import { ArchivedFeatureReviveConfirm } from '../../../../archive/ArchiveTable/ArchivedFeatureActionCell/ArchivedFeatureReviveConfirm/ArchivedFeatureReviveConfirm';
export const useRowActions = (onChange: () => void, projectId: string) => { export const useRowActions = (onChange: () => void, projectId: string) => {
const [featureArchiveState, setFeatureArchiveState] = useState< const [featureArchiveState, setFeatureArchiveState] = useState<
@ -20,6 +22,21 @@ export const useRowActions = (onChange: () => void, projectId: string) => {
featureId: 'default', featureId: 'default',
open: false, open: false,
}); });
const [showFeatureReviveDialogue, setShowFeatureReviveDialogue] = useState<{
featureId: string;
open: boolean;
}>({
featureId: 'default',
open: false,
});
const [showFeatureDeleteDialogue, setShowFeatureDeleteDialogue] = useState<{
featureId: string;
open: boolean;
}>({
featureId: 'default',
open: false,
});
const rowActionsDialogs = ( const rowActionsDialogs = (
<> <>
<FeatureStaleDialog <FeatureStaleDialog
@ -54,6 +71,36 @@ export const useRowActions = (onChange: () => void, projectId: string) => {
featureId={showMarkCompletedDialogue.featureId} featureId={showMarkCompletedDialogue.featureId}
onComplete={onChange} onComplete={onChange}
/> />
<ArchivedFeatureDeleteConfirm
deletedFeatures={[showFeatureDeleteDialogue.featureId]}
projectId={projectId}
open={showFeatureDeleteDialogue.open}
setOpen={(open) => {
setShowFeatureDeleteDialogue((prev) => ({
...prev,
open,
}));
}}
refetch={onChange}
/>
<ArchivedFeatureReviveConfirm
revivedFeatures={[showFeatureReviveDialogue.featureId]}
projectId={projectId}
open={showFeatureReviveDialogue.open}
setOpen={(open) => {
setShowFeatureReviveDialogue((prev) => ({
...prev,
open,
}));
}}
refetch={() => {
setShowFeatureReviveDialogue((prev) => ({
...prev,
open: false,
}));
onChange();
}}
/>
</> </>
); );
@ -62,5 +109,7 @@ export const useRowActions = (onChange: () => void, projectId: string) => {
setFeatureArchiveState, setFeatureArchiveState,
setFeatureStaleDialogState, setFeatureStaleDialogState,
setShowMarkCompletedDialogue, setShowMarkCompletedDialogue,
setShowFeatureReviveDialogue,
setShowFeatureDeleteDialogue,
}; };
}; };

View File

@ -91,6 +91,7 @@ export type UiFlags = {
purchaseAdditionalEnvironments?: boolean; purchaseAdditionalEnvironments?: boolean;
unleashAI?: boolean; unleashAI?: boolean;
releasePlans?: boolean; releasePlans?: boolean;
simplifyProjectOverview?: boolean;
}; };
export interface IVersionInfo { export interface IVersionInfo {

View File

@ -42,7 +42,7 @@ export interface EventSchema {
*/ */
id: number; id: number;
/** /**
* **[Experimental]** The concise, human-readable name of the event. * The concise, human-readable name of the event.
* @nullable * @nullable
*/ */
label?: string | null; label?: string | null;
@ -57,7 +57,7 @@ export interface EventSchema {
*/ */
project?: string | null; project?: string | null;
/** /**
* **[Experimental]** A markdown-formatted summary of the event. * A markdown-formatted summary of the event.
* @nullable * @nullable
*/ */
summary?: string | null; summary?: string | null;

View File

@ -15,8 +15,6 @@ import type { VariantSchema } from './variantSchema';
* A feature flag definition * A feature flag definition
*/ */
export interface FeatureSearchResponseSchema { export interface FeatureSearchResponseSchema {
/** `true` if the feature is archived */
archived?: boolean;
/** /**
* The date the feature was archived * The date the feature was archived
* @nullable * @nullable

View File

@ -5,7 +5,7 @@
*/ */
/** /**
* A [feature flag type](https://docs.getunleash.io/reference/feature-toggles#feature-flag-types. * A [feature flag type](https://docs.getunleash.io/reference/feature-toggles#feature-flag-types).
*/ */
export interface FeatureTypeSchema { export interface FeatureTypeSchema {
/** A description of what this feature flag type is intended to be used for. */ /** A description of what this feature flag type is intended to be used for. */

View File

@ -13,7 +13,7 @@ import type { PersonalDashboardProjectDetailsSchemaRolesItem } from './personalD
* Project details in personal dashboard * Project details in personal dashboard
*/ */
export interface PersonalDashboardProjectDetailsSchema { export interface PersonalDashboardProjectDetailsSchema {
/** Insights for the project */ /** Insights for the project, including flag data and project health information. */
insights: PersonalDashboardProjectDetailsSchemaInsights; insights: PersonalDashboardProjectDetailsSchemaInsights;
/** The latest events for the project. */ /** The latest events for the project. */
latestEvents: PersonalDashboardProjectDetailsSchemaLatestEventsItem[]; latestEvents: PersonalDashboardProjectDetailsSchemaLatestEventsItem[];
@ -21,8 +21,6 @@ export interface PersonalDashboardProjectDetailsSchema {
onboardingStatus: PersonalDashboardProjectDetailsSchemaOnboardingStatus; onboardingStatus: PersonalDashboardProjectDetailsSchemaOnboardingStatus;
/** The users and/or groups that have the "owner" role in this project. If no such users or groups exist, the list will contain the "system" owner instead. */ /** The users and/or groups that have the "owner" role in this project. If no such users or groups exist, the list will contain the "system" owner instead. */
owners: PersonalDashboardProjectDetailsSchemaOwners; owners: PersonalDashboardProjectDetailsSchemaOwners;
/** /** The list of roles that the user has in this project. */
* The list of roles that the user has in this project.
*/
roles: PersonalDashboardProjectDetailsSchemaRolesItem[]; roles: PersonalDashboardProjectDetailsSchemaRolesItem[];
} }

View File

@ -5,22 +5,44 @@
*/ */
/** /**
* Insights for the project * Insights for the project, including flag data and project health information.
*/ */
export type PersonalDashboardProjectDetailsSchemaInsights = { export type PersonalDashboardProjectDetailsSchemaInsights = {
/** /**
* The average health score in the current window of the last 4 weeks * The number of active flags that are not stale or potentially stale
* @minimum 0
*/
activeFlags: number;
/**
* The project's average health score over the last 4 weeks
* @minimum 0
* @nullable * @nullable
*/ */
avgHealthCurrentWindow: number | null; avgHealthCurrentWindow: number | null;
/** /**
* The average health score in the previous 4 weeks before the current window * The project's average health score over the previous 4-week window
* @minimum 0
* @nullable * @nullable
*/ */
avgHealthPastWindow: number | null; avgHealthPastWindow: number | null;
totalFlags: number; /**
activeFlags: number; * The project's current health score
staleFlags: number; * @minimum 0
potentiallyStaleFlags: number; */
health: number; health: number;
/**
* The number of potentially stale flags as calculated by Unleash
* @minimum 0
*/
potentiallyStaleFlags: number;
/**
* The current number of flags that have been manually marked as stale
* @minimum 0
*/
staleFlags: number;
/**
* The current number of non-archived flags
* @minimum 0
*/
totalFlags: number;
}; };

View File

@ -8,6 +8,8 @@
* An event summary * An event summary
*/ */
export type PersonalDashboardProjectDetailsSchemaLatestEventsItem = { export type PersonalDashboardProjectDetailsSchemaLatestEventsItem = {
/** When the event was recorded */
createdAt: string;
/** Which user created this event */ /** Which user created this event */
createdBy: string; createdBy: string;
/** URL used for the user profile image of the event author */ /** URL used for the user profile image of the event author */
@ -22,5 +24,4 @@ export type PersonalDashboardProjectDetailsSchemaLatestEventsItem = {
* @nullable * @nullable
*/ */
summary: string | null; summary: string | null;
createdAt: string;
}; };

View File

@ -14,6 +14,4 @@ export type PersonalDashboardProjectDetailsSchemaRolesItemType =
export const PersonalDashboardProjectDetailsSchemaRolesItemType = { export const PersonalDashboardProjectDetailsSchemaRolesItemType = {
custom: 'custom', custom: 'custom',
project: 'project', project: 'project',
root: 'root',
'custom-root': 'custom-root',
} as const; } as const;

View File

@ -5,13 +5,22 @@
*/ */
export type PersonalDashboardSchemaProjectsItem = { export type PersonalDashboardSchemaProjectsItem = {
/** The number of features this project has */ /**
* The number of features this project has
* @minimum 0
*/
featureCount: number; featureCount: number;
/** An indicator of the [project's health](https://docs.getunleash.io/reference/technical-debt#health-rating) on a scale from 0 to 100 */ /**
* An indicator of the [project's health](https://docs.getunleash.io/reference/technical-debt#health-rating) on a scale from 0 to 100
* @minimum 0
*/
health: number; health: number;
/** The id of the project */ /** The id of the project */
id: string; id: string;
/** The number of members this project has */ /**
* The number of members this project has
* @minimum 0
*/
memberCount: number; memberCount: number;
/** The name of the project */ /** The name of the project */
name: string; name: string;

View File

@ -58,6 +58,10 @@ export type SearchFeaturesParams = {
* The flag to indicate if the favorite features should be returned first. By default it is set to false. * The flag to indicate if the favorite features should be returned first. By default it is set to false.
*/ */
favoritesFirst?: string; favoritesFirst?: string;
/**
* Whether to get results for archived feature flags or active feature flags. If `true`, Unleash will return only archived flags. If `false`, it will return only active flags.
*/
archived?: string;
/** /**
* The date the feature was created. The date can be specified with an operator. The supported operators are IS_BEFORE, IS_ON_OR_AFTER. * The date the feature was created. The date can be specified with an operator. The supported operators are IS_BEFORE, IS_ON_OR_AFTER.
*/ */

View File

@ -55,6 +55,8 @@ export interface UiConfigSchema {
* @deprecated * @deprecated
*/ */
strategySegmentsLimit?: number; strategySegmentsLimit?: number;
/** Whether Unleash AI is available. */
unleashAIAvailable?: boolean;
/** The URL of the Unleash instance. */ /** The URL of the Unleash instance. */
unleashUrl: string; unleashUrl: string;
/** The current version of Unleash */ /** The current version of Unleash */

View File

@ -1383,48 +1383,49 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@inquirer/confirm@npm:^3.0.0": "@inquirer/confirm@npm:^4.0.0":
version: 3.1.9 version: 4.0.1
resolution: "@inquirer/confirm@npm:3.1.9" resolution: "@inquirer/confirm@npm:4.0.1"
dependencies: dependencies:
"@inquirer/core": "npm:^8.2.2" "@inquirer/core": "npm:^9.2.1"
"@inquirer/type": "npm:^1.3.3" "@inquirer/type": "npm:^2.0.0"
checksum: 10c0/9fb63a052cbe3705bcab706b3e68d70aa75ac7c7bfc04cc4fee2319e4da9355150c99b205bc72b595844e1549705643049e71d14070a3ab3d6483941c1e6a239 checksum: 10c0/8ea5e6a63efa348b626750384c249cc903280e38c2596bb42c640f178b375dbc389d8c4d040b2e4759b3937d8a188e245ca262b8dc7cdb2fa35dfce4104c2e8f
languageName: node languageName: node
linkType: hard linkType: hard
"@inquirer/core@npm:^8.2.2": "@inquirer/core@npm:^9.2.1":
version: 8.2.2 version: 9.2.1
resolution: "@inquirer/core@npm:8.2.2" resolution: "@inquirer/core@npm:9.2.1"
dependencies: dependencies:
"@inquirer/figures": "npm:^1.0.3" "@inquirer/figures": "npm:^1.0.6"
"@inquirer/type": "npm:^1.3.3" "@inquirer/type": "npm:^2.0.0"
"@types/mute-stream": "npm:^0.0.4" "@types/mute-stream": "npm:^0.0.4"
"@types/node": "npm:^20.12.13" "@types/node": "npm:^22.5.5"
"@types/wrap-ansi": "npm:^3.0.0" "@types/wrap-ansi": "npm:^3.0.0"
ansi-escapes: "npm:^4.3.2" ansi-escapes: "npm:^4.3.2"
chalk: "npm:^4.1.2"
cli-spinners: "npm:^2.9.2"
cli-width: "npm:^4.1.0" cli-width: "npm:^4.1.0"
mute-stream: "npm:^1.0.0" mute-stream: "npm:^1.0.0"
signal-exit: "npm:^4.1.0" signal-exit: "npm:^4.1.0"
strip-ansi: "npm:^6.0.1" strip-ansi: "npm:^6.0.1"
wrap-ansi: "npm:^6.2.0" wrap-ansi: "npm:^6.2.0"
checksum: 10c0/6a04b42f856b31f892bd2195cbb214a38836f708f09925b36a50b11e3e84dca73ebf008ff7a42f2e7901350450a1cec8fe625c43cc1a90eda3c10ed7e4527cca yoctocolors-cjs: "npm:^2.1.2"
checksum: 10c0/11c14be77a9fa85831de799a585721b0a49ab2f3b7d8fd1780c48ea2b29229c6bdc94e7892419086d0f7734136c2ba87b6a32e0782571eae5bbd655b1afad453
languageName: node languageName: node
linkType: hard linkType: hard
"@inquirer/figures@npm:^1.0.3": "@inquirer/figures@npm:^1.0.6":
version: 1.0.3 version: 1.0.7
resolution: "@inquirer/figures@npm:1.0.3" resolution: "@inquirer/figures@npm:1.0.7"
checksum: 10c0/099e062f000baafb4010014ece443d0cd211f562194854dc52a128bfe514611f8cc3da4cdb5092d75440956aff201dcd8e893b8a71feb104f97b0b00c6a696cf checksum: 10c0/d7b4cfcd38dd43d1ac79da52c4478aa89145207004a471aa2083856f1d9b99adef45563f09d66c09d6457b09200fcf784527804b70ad3bd517cbc5e11142c2df
languageName: node languageName: node
linkType: hard linkType: hard
"@inquirer/type@npm:^1.3.3": "@inquirer/type@npm:^2.0.0":
version: 1.3.3 version: 2.0.0
resolution: "@inquirer/type@npm:1.3.3" resolution: "@inquirer/type@npm:2.0.0"
checksum: 10c0/84048694410bb5b2c55dc4e48da6369ce942b9e8f8016d15ef63ab3f9873832a56cc12a50582b5b2b626821bfe29973dfcc19edc90f58490b51df1f4d9d0a074 dependencies:
mute-stream: "npm:^1.0.0"
checksum: 10c0/8c663d52beb2b89a896d3c3d5cc3d6d024fa149e565555bcb42fa640cbe23fba7ff2c51445342cef1fe6e46305e2d16c1590fa1d11ad0ddf93a67b655ef41f0a
languageName: node languageName: node
linkType: hard linkType: hard
@ -3084,7 +3085,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/node@npm:^20.12.12, @types/node@npm:^20.12.13": "@types/node@npm:^20.12.12":
version: 20.17.1 version: 20.17.1
resolution: "@types/node@npm:20.17.1" resolution: "@types/node@npm:20.17.1"
dependencies: dependencies:
@ -3093,6 +3094,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/node@npm:^22.5.5":
version: 22.8.4
resolution: "@types/node@npm:22.8.4"
dependencies:
undici-types: "npm:~6.19.8"
checksum: 10c0/f88d030480630194a9168772462ec09b2d86454f34368c46d2b7fda5dc6e14594b1576fcc5c35cc53b57a4d1e8dd2865a85ae81f34ded0d1af753a0f5d294c25
languageName: node
linkType: hard
"@types/parse-json@npm:^4.0.0": "@types/parse-json@npm:^4.0.0":
version: 4.0.2 version: 4.0.2
resolution: "@types/parse-json@npm:4.0.2" resolution: "@types/parse-json@npm:4.0.2"
@ -4143,13 +4153,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"cli-spinners@npm:^2.9.2":
version: 2.9.2
resolution: "cli-spinners@npm:2.9.2"
checksum: 10c0/907a1c227ddf0d7a101e7ab8b300affc742ead4b4ebe920a5bf1bc6d45dce2958fcd195eb28fa25275062fe6fa9b109b93b63bc8033396ed3bcb50297008b3a3
languageName: node
linkType: hard
"cli-table3@npm:~0.6.1": "cli-table3@npm:~0.6.1":
version: 0.6.5 version: 0.6.5
resolution: "cli-table3@npm:0.6.5" resolution: "cli-table3@npm:0.6.5"
@ -6737,9 +6740,9 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"jsonpath-plus@npm:10.0.0": "jsonpath-plus@npm:10.1.0":
version: 10.0.0 version: 10.1.0
resolution: "jsonpath-plus@npm:10.0.0" resolution: "jsonpath-plus@npm:10.1.0"
dependencies: dependencies:
"@jsep-plugin/assignment": "npm:^1.2.1" "@jsep-plugin/assignment": "npm:^1.2.1"
"@jsep-plugin/regex": "npm:^1.0.3" "@jsep-plugin/regex": "npm:^1.0.3"
@ -6747,7 +6750,7 @@ __metadata:
bin: bin:
jsonpath: bin/jsonpath-cli.js jsonpath: bin/jsonpath-cli.js
jsonpath-plus: bin/jsonpath-cli.js jsonpath-plus: bin/jsonpath-cli.js
checksum: 10c0/0bd0ad79397f319c8543f090a944ea08c933c13d69ad5213f202f738ef4abd46de57c917844a83e2e89643cadbfc2e327a402c01eaf50bd1870882d50a4a8b95 checksum: 10c0/1ff0743f9113f7750b598563c7886e1b07c19f112c4a8d976165e6799ff9774279985d1f4a147e87eacc0b94eb27dbd6e3ab5cf0728d4ba947f00757bc6aebb4
languageName: node languageName: node
linkType: hard linkType: hard
@ -7609,14 +7612,14 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"msw@npm:2.4.12": "msw@npm:2.5.0":
version: 2.4.12 version: 2.5.0
resolution: "msw@npm:2.4.12" resolution: "msw@npm:2.5.0"
dependencies: dependencies:
"@bundled-es-modules/cookie": "npm:^2.0.0" "@bundled-es-modules/cookie": "npm:^2.0.0"
"@bundled-es-modules/statuses": "npm:^1.0.1" "@bundled-es-modules/statuses": "npm:^1.0.1"
"@bundled-es-modules/tough-cookie": "npm:^0.1.6" "@bundled-es-modules/tough-cookie": "npm:^0.1.6"
"@inquirer/confirm": "npm:^3.0.0" "@inquirer/confirm": "npm:^4.0.0"
"@mswjs/interceptors": "npm:^0.36.5" "@mswjs/interceptors": "npm:^0.36.5"
"@open-draft/until": "npm:^2.1.0" "@open-draft/until": "npm:^2.1.0"
"@types/cookie": "npm:^0.6.0" "@types/cookie": "npm:^0.6.0"
@ -7637,7 +7640,7 @@ __metadata:
optional: true optional: true
bin: bin:
msw: cli/index.js msw: cli/index.js
checksum: 10c0/1f24544e5aaac4a5184cae48ee4f6f8a85d1476f361cb7b831fcabfb4cdedbb03a38298c1b1c3af77118c439b797d8a95e2398ba1c233cf353be496de1a0ef9c checksum: 10c0/59eb6d2496b4d44f6b5507802beffd780ac03efc0b02cc092886d1ff6b9266297274ee655cf89bcccc49988d960f685f0dd571535663bc7f60f38e8040d9a092
languageName: node languageName: node
linkType: hard linkType: hard
@ -10153,7 +10156,7 @@ __metadata:
lodash.mapvalues: "npm:^4.6.0" lodash.mapvalues: "npm:^4.6.0"
lodash.omit: "npm:4.5.0" lodash.omit: "npm:4.5.0"
millify: "npm:^6.0.0" millify: "npm:^6.0.0"
msw: "npm:2.4.12" msw: "npm:2.5.0"
orval: "npm:^6.31.0" orval: "npm:^6.31.0"
pkginfo: "npm:0.4.1" pkginfo: "npm:0.4.1"
plausible-tracker: "npm:0.3.9" plausible-tracker: "npm:0.3.9"
@ -10178,7 +10181,7 @@ __metadata:
typescript: "npm:5.4.5" typescript: "npm:5.4.5"
use-query-params: "npm:^2.2.1" use-query-params: "npm:^2.2.1"
vanilla-jsoneditor: "npm:^0.23.0" vanilla-jsoneditor: "npm:^0.23.0"
vite: "npm:5.4.9" vite: "npm:5.4.10"
vite-plugin-env-compatible: "npm:2.0.1" vite-plugin-env-compatible: "npm:2.0.1"
vite-plugin-svgr: "npm:3.3.0" vite-plugin-svgr: "npm:3.3.0"
vite-tsconfig-paths: "npm:4.3.2" vite-tsconfig-paths: "npm:4.3.2"
@ -10451,9 +10454,9 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"vite@npm:5.4.9": "vite@npm:5.4.10":
version: 5.4.9 version: 5.4.10
resolution: "vite@npm:5.4.9" resolution: "vite@npm:5.4.10"
dependencies: dependencies:
esbuild: "npm:^0.21.3" esbuild: "npm:^0.21.3"
fsevents: "npm:~2.3.3" fsevents: "npm:~2.3.3"
@ -10490,7 +10493,7 @@ __metadata:
optional: true optional: true
bin: bin:
vite: bin/vite.js vite: bin/vite.js
checksum: 10c0/e9c59f2c639047e37c79bbbb151c7a55a3dc27932957cf4cf0447ee0bdcc1ddfd9b1fb3ba0465371c01ba3616d62561327855794c2d652213c3a10a32e6d369d checksum: 10c0/4ef4807d2fd166a920de244dbcec791ba8a903b017a7d8e9f9b4ac40d23f8152c1100610583d08f542b47ca617a0505cfc5f8407377d610599d58296996691ed
languageName: node languageName: node
linkType: hard linkType: hard
@ -10836,6 +10839,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"yoctocolors-cjs@npm:^2.1.2":
version: 2.1.2
resolution: "yoctocolors-cjs@npm:2.1.2"
checksum: 10c0/a0e36eb88fea2c7981eab22d1ba45e15d8d268626e6c4143305e2c1628fa17ebfaa40cd306161a8ce04c0a60ee0262058eab12567493d5eb1409780853454c6f
languageName: node
linkType: hard
"zustand@npm:4.0.0": "zustand@npm:4.0.0":
version: 4.0.0 version: 4.0.0
resolution: "zustand@npm:4.0.0" resolution: "zustand@npm:4.0.0"

View File

@ -173,7 +173,7 @@
}, },
"devDependencies": { "devDependencies": {
"@apidevtools/swagger-parser": "10.1.0", "@apidevtools/swagger-parser": "10.1.0",
"@babel/core": "7.25.8", "@babel/core": "7.25.9",
"@biomejs/biome": "^1.8.3", "@biomejs/biome": "^1.8.3",
"@cyclonedx/yarn-plugin-cyclonedx": "^1.0.0-rc.7", "@cyclonedx/yarn-plugin-cyclonedx": "^1.0.0-rc.7",
"@swc/core": "1.7.39", "@swc/core": "1.7.39",
@ -191,7 +191,7 @@
"@types/memoizee": "0.4.11", "@types/memoizee": "0.4.11",
"@types/mime": "4.0.0", "@types/mime": "4.0.0",
"@types/mustache": "^4.2.5", "@types/mustache": "^4.2.5",
"@types/node": "20.16.13", "@types/node": "20.16.14",
"@types/nodemailer": "6.4.16", "@types/nodemailer": "6.4.16",
"@types/owasp-password-strength-test": "1.3.2", "@types/owasp-password-strength-test": "1.3.2",
"@types/pg": "8.11.10", "@types/pg": "8.11.10",

View File

@ -94,13 +94,11 @@ export default abstract class Addon {
integrationEvent: IntegrationEventWriteModel, integrationEvent: IntegrationEventWriteModel,
): Promise<void> { ): Promise<void> {
await this.integrationEventsService.registerEvent(integrationEvent); await this.integrationEventsService.registerEvent(integrationEvent);
if (this.flagResolver.isEnabled('addonUsageMetrics')) {
this.eventBus.emit(ADDON_EVENTS_HANDLED, { this.eventBus.emit(ADDON_EVENTS_HANDLED, {
result: integrationEvent.state, result: integrationEvent.state,
destination: this.name, destination: this.name,
}); });
} }
}
destroy?(): void; destroy?(): void;
} }

View File

@ -111,10 +111,8 @@ export default class EventSearchController extends Controller {
} }
enrichEvents(events: IEvent[]): IEvent[] | IEnrichedEvent[] { enrichEvents(events: IEvent[]): IEvent[] | IEnrichedEvent[] {
if (this.flagResolver.isEnabled('eventTimeline')) {
return events.map((event) => { return events.map((event) => {
const { label, text: summary } = const { label, text: summary } = this.msgFormatter.format(event);
this.msgFormatter.format(event);
return { return {
...event, ...event,
@ -123,8 +121,6 @@ export default class EventSearchController extends Controller {
}; };
}); });
} }
return events;
}
maybeAnonymiseEvents(events: IEvent[]): IEvent[] { maybeAnonymiseEvents(events: IEvent[]): IEvent[] {
if (this.flagResolver.isEnabled('anonymiseEventLog')) { if (this.flagResolver.isEnabled('anonymiseEventLog')) {

View File

@ -121,6 +121,7 @@ class FeatureSearchStore implements IFeatureSearchStore {
'features.name as feature_name', 'features.name as feature_name',
'features.description as description', 'features.description as description',
'features.type as type', 'features.type as type',
'features.archived_at as archived_at',
'features.project as project', 'features.project as project',
'features.created_at as created_at', 'features.created_at as created_at',
'features.stale as stale', 'features.stale as stale',
@ -475,6 +476,7 @@ class FeatureSearchStore implements IFeatureSearchStore {
name: row.feature_name, name: row.feature_name,
createdAt: row.created_at, createdAt: row.created_at,
stale: row.stale, stale: row.stale,
archivedAt: row.archived_at,
impressionData: row.impression_data, impressionData: row.impression_data,
lastSeenAt: row.last_seen_at, lastSeenAt: row.last_seen_at,
dependencyType: row.dependency, dependencyType: row.dependency,

View File

@ -179,6 +179,11 @@ const filterFeaturesByEnvironmentStatus = async (
const searchFeaturesWithoutQueryParams = async (expectedCode = 200) => { const searchFeaturesWithoutQueryParams = async (expectedCode = 200) => {
return app.request.get(`/api/admin/search/features`).expect(expectedCode); return app.request.get(`/api/admin/search/features`).expect(expectedCode);
}; };
const getProjectArchive = async (projectId = 'default', expectedCode = 200) => {
return app.request
.get(`/api/admin/archive/features/${projectId}`)
.expect(expectedCode);
};
test('should search matching features by name', async () => { test('should search matching features by name', async () => {
await app.createFeature('my_feature_a'); await app.createFeature('my_feature_a');
@ -1154,6 +1159,7 @@ test('should return archived when query param set', async () => {
features: [ features: [
{ {
name: 'my_feature_a', name: 'my_feature_a',
archivedAt: null,
}, },
], ],
}); });
@ -1162,10 +1168,14 @@ test('should return archived when query param set', async () => {
query: 'my_feature', query: 'my_feature',
archived: 'IS:true', archived: 'IS:true',
}); });
const { body: archive } = await getProjectArchive();
expect(archivedFeatures).toMatchObject({ expect(archivedFeatures).toMatchObject({
features: [ features: [
{ {
name: 'my_feature_b', name: 'my_feature_b',
archivedAt: archive.features[0].archivedAt,
}, },
], ],
}); });

View File

@ -95,14 +95,12 @@ export const eventSchema = {
label: { label: {
type: 'string', type: 'string',
nullable: true, nullable: true,
description: description: 'The concise, human-readable name of the event.',
'**[Experimental]** The concise, human-readable name of the event.',
}, },
summary: { summary: {
type: 'string', type: 'string',
nullable: true, nullable: true,
description: description: 'A markdown-formatted summary of the event.',
'**[Experimental]** A markdown-formatted summary of the event.',
}, },
}, },
components: { components: {

View File

@ -54,11 +54,6 @@ export const featureSearchResponseSchema = {
description: description:
"The type of dependency. 'parent' means that the feature is a parent feature, 'child' means that the feature is a child feature.", "The type of dependency. 'parent' means that the feature is a parent feature, 'child' means that the feature is a child feature.",
}, },
archived: {
type: 'boolean',
example: true,
description: '`true` if the feature is archived',
},
project: { project: {
type: 'string', type: 'string',
example: 'dx-squad', example: 'dx-squad',

View File

@ -51,17 +51,16 @@ export type IFlagKey =
| 'removeUnsafeInlineStyleSrc' | 'removeUnsafeInlineStyleSrc'
| 'onboardingUI' | 'onboardingUI'
| 'projectRoleAssignment' | 'projectRoleAssignment'
| 'eventTimeline'
| 'personalDashboardUI' | 'personalDashboardUI'
| 'trackLifecycleMetrics' | 'trackLifecycleMetrics'
| 'purchaseAdditionalEnvironments' | 'purchaseAdditionalEnvironments'
| 'originMiddlewareRequestLogging' | 'originMiddlewareRequestLogging'
| 'unleashAI' | 'unleashAI'
| 'webhookDomainLogging' | 'webhookDomainLogging'
| 'addonUsageMetrics'
| 'releasePlans' | 'releasePlans'
| 'navigationSidebar' | 'navigationSidebar'
| 'productivityReportEmail'; | 'productivityReportEmail'
| 'simplifyProjectOverview';
export type IFlags = Partial<{ [key in IFlagKey]: boolean | Variant }>; export type IFlags = Partial<{ [key in IFlagKey]: boolean | Variant }>;
@ -262,10 +261,6 @@ const flags: IFlags = {
process.env.UNLEASH_EXPERIMENTAL_PROJECT_ROLE_ASSIGNMENT, process.env.UNLEASH_EXPERIMENTAL_PROJECT_ROLE_ASSIGNMENT,
false, false,
), ),
eventTimeline: parseEnvVarBoolean(
process.env.UNLEASH_EXPERIMENTAL_EVENT_TIMELINE,
false,
),
personalDashboardUI: parseEnvVarBoolean( personalDashboardUI: parseEnvVarBoolean(
process.env.UNLEASH_EXPERIMENTAL_PERSONAL_DASHBOARD_UI, process.env.UNLEASH_EXPERIMENTAL_PERSONAL_DASHBOARD_UI,
false, false,
@ -290,10 +285,6 @@ const flags: IFlags = {
process.env.UNLEASH_EXPERIMENT_WEBHOOK_DOMAIN_LOGGING, process.env.UNLEASH_EXPERIMENT_WEBHOOK_DOMAIN_LOGGING,
false, false,
), ),
addonUsageMetrics: parseEnvVarBoolean(
process.env.UNLEASH_EXPERIMENTAL_ADDON_USAGE_METRICS,
false,
),
releasePlans: parseEnvVarBoolean( releasePlans: parseEnvVarBoolean(
process.env.UNLEASH_EXPERIMENTAL_RELEASE_PLANS, process.env.UNLEASH_EXPERIMENTAL_RELEASE_PLANS,
false, false,
@ -306,6 +297,10 @@ const flags: IFlags = {
process.env.UNLEASH_EXPERIMENTAL_PRODUCTIVITY_REPORT_EMAIL, process.env.UNLEASH_EXPERIMENTAL_PRODUCTIVITY_REPORT_EMAIL,
false, false,
), ),
simplifyProjectOverview: parseEnvVarBoolean(
process.env.UNLEASH_EXPERIMENTAL_SIMPLIFY_PROJECT_OVERVIEW,
false,
),
}; };
export const defaultExperimentalOptions: IExperimentalOptions = { export const defaultExperimentalOptions: IExperimentalOptions = {

View File

@ -261,6 +261,7 @@ export type IFeatureSearchOverview = Exclude<
> & { > & {
dependencyType: 'parent' | 'child' | null; dependencyType: 'parent' | 'child' | null;
environments: FeatureSearchEnvironmentSchema[]; environments: FeatureSearchEnvironmentSchema[];
archivedAt: string;
createdBy: { createdBy: {
id: number; id: number;
name: string; name: string;

View File

@ -73,7 +73,7 @@
<div class="unsubscribe" style="font-size: 12px;color: #888;margin-top: 10px;"> <div class="unsubscribe" style="font-size: 12px;color: #888;margin-top: 10px;">
This email was sent to {{userEmail}}. Youve received this as you are a user of Unleash.<br> This email was sent to {{userEmail}}. Youve received this as you are a user of Unleash.<br>
{{#unsubscribeUrl}} {{#unsubscribeUrl}}
If you wish to unsubscribe from updated, click <a href="{{unsubscribeUrl}}">here</a>. If you wish to unsubscribe, click <a href="{{unsubscribeUrl}}">here</a>.
{{/unsubscribeUrl}} {{/unsubscribeUrl}}
</div> </div>
</div> </div>

View File

@ -1,10 +1,19 @@
Subject: Unleash productivity report Subject: Unleash Productivity Report
Hello, Hi {{userName}},
Productivity report We are excited to share the latest insights for your instance. As always if you
{{! FIXME: create plaintext template }} have any questions or concerns let us know - we are here for you.
Your instance health: {{health}}
Flags created last month: {{flagsCreated}}
Production updates last month: {{productionUpdates}}
Go to your Insights to learn more: {{unleashUrl}}/insights
This email was sent to {{userEmail}}. Youve received this as you are a user of Unleash.
{{#unsubscribeUrl}} {{#unsubscribeUrl}}
If you wish to unsubscribe from updated, open {{unsubscribeUrl}}. If you wish to unsubscribe, click <a href="{{unsubscribeUrl}}">here</a>.
{{/unsubscribeUrl}} {{/unsubscribeUrl}}

View File

@ -0,0 +1,27 @@
exports.up = function(db, cb) {
db.runSql(`
ALTER TABLE release_plan_definitions ADD COLUMN release_plan_template_id TEXT REFERENCES release_plan_definitions(id) ON DELETE CASCADE;
CREATE INDEX idx_release_plan_template_definition_id ON release_plan_definitions (release_plan_template_id) WHERE release_plan_template_id IS NOT NULL;
ALTER TABLE feature_strategies ADD COLUMN milestone_id TEXT REFERENCES milestones(id) ON DELETE CASCADE;
CREATE INDEX idx_feature_strategies_milestone_id ON feature_strategies (milestone_id) WHERE milestone_id IS NOT NULL;
CREATE TABLE milestone_strategy_segments (
segment_id INT NOT NULL references segments(id) ON DELETE CASCADE,
milestone_strategy_id TEXT NOT NULL references milestone_strategies(id) ON DELETE CASCADE,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT (now() at time zone 'utc'),
PRIMARY KEY (segment_id, milestone_strategy_id)
);
ALTER TABLE milestone_strategies ADD COLUMN variants JSONB NOT NULL DEFAULT '[]'::JSONB;
`, cb)
};
exports.down = function(db, cb) {
db.runSql(`
ALTER TABLE release_plan_definitions DROP COLUMN release_plan_template_id;
ALTER TABLE feature_strategies DROP COLUMN milestone_id;
DROP TABLE milestone_strategy_segments;
ALTER TABLE milestone_strategies DROP COLUMN variants;
`, cb);
};

View File

@ -55,8 +55,8 @@ process.nextTick(async () => {
originMiddlewareRequestLogging: true, originMiddlewareRequestLogging: true,
unleashAI: true, unleashAI: true,
webhookDomainLogging: true, webhookDomainLogging: true,
addonUsageMetrics: true,
releasePlans: false, releasePlans: false,
simplifyProjectOverview: true,
}, },
}, },
authentication: { authentication: {

2
website/.gitignore vendored
View File

@ -20,7 +20,7 @@ yarn-debug.log*
yarn-error.log* yarn-error.log*
# OpenAPI docusaurus generated stuff # OpenAPI docusaurus generated stuff
docs/reference/api/**/sidebar.js docs/reference/api/**/sidebar.ts
*.api.mdx *.api.mdx
*.tag.mdx *.tag.mdx

View File

@ -1,3 +0,0 @@
module.exports = {
presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
};

View File

@ -15,7 +15,7 @@
// the bits that are specific to the generation source we use, and make the docs // the bits that are specific to the generation source we use, and make the docs
// easier to use. In particular, removing the leading `/ushosted` is likely to // easier to use. In particular, removing the leading `/ushosted` is likely to
// save us loooots of questions. // save us loooots of questions.
const replace = require('replace-in-file'); import { replaceInFileSync } from 'replace-in-file';
const options = { const options = {
files: 'docs/reference/api/**/*.api.mdx', files: 'docs/reference/api/**/*.api.mdx',
@ -27,4 +27,4 @@ const options = {
to: ['', '"<your-unleash-url>"', '"path":['], to: ['', '"<your-unleash-url>"', '"path":['],
}; };
replace(options); replaceInFileSync(options);

View File

@ -13,12 +13,14 @@ In this tutorial, you will learn how to set up and use iOS feature flags with Un
Here are the steps we will cover in this tutorial: Here are the steps we will cover in this tutorial:
1. [Feature flag best practices for client-side apps](#1-architect-to-limit-pii-and-configuration-leakage) - [Prerequisites](#prerequisites)
2. [Spin up a local provider](#2-install-a-local-feature-flag-provider) - [1. Architect to limit PII and configuration leakage](#1-architect-to-limit-pii-and-configuration-leakage)
3. [Configure a feature flag](#3-create-and-configure-the-feature-flag) - [2. Install a local feature flag provider](#2-install-a-local-feature-flag-provider)
4. [Add Unleash to an iOS app](#4-add-unleash-to-an-ios-app) - [3. Create and configure the feature flag](#3-create-and-configure-the-feature-flag)
5. [Log status of iOS feature flag](#5-configure-unleash-and-log-ios-feature-flag-status) - [4. Add Unleash to an iOS app](#4-add-unleash-to-an-ios-app)
6. [Verify the feature flag experience](#6-verify-the-feature-flag-experience) - [5. Configure Unleash and log iOS feature flag status](#5-configure-unleash-and-log-ios-feature-flag-status)
- [6. Verify the feature flag experience](#6-verify-the-feature-flag-experience)
- [Conclusion](#conclusion)
## Prerequisites ## Prerequisites
@ -37,7 +39,7 @@ a. Limit PII (personally identifiable information) leakage from the end-user dev
b. Avoid leakage of configuration information from the central feature flag control service to end-user devices. b. Avoid leakage of configuration information from the central feature flag control service to end-user devices.
Solving both means you need to avoid evaluating feature flags on the user's machine due to security risks like exposing API keys and flag data. Instead, send application context (e.g. username, location, etc) to your feature flag evaluation service to evaluate the results. These results (and only these results) should be stored in the client-side application memory. By keeping the evaluated results for a specific context in memory, you avoid network roundtrips every time your application needs to check the status of a feature flag. This method prevents unauthorized access and data breaches by [keeping configurations and PII secure](/topics/feature-flags/never-expose-pii). Solving both means you need to avoid evaluating feature flags on the user's machine due to security risks like exposing API keys and flag data. Instead, send application context (e.g. username, location, etc) to your feature flag evaluation service to evaluate the results. These results (and only these results) should be stored in the client-side application memory. By keeping the evaluated results for a specific context in memory, you avoid network roundtrips every time your application needs to check the status of a feature flag. This method prevents unauthorized access and data breaches by [keeping configurations and PII secure](/topics/feature-flags/feature-flag-best-practices#2-protect-pii-by-evaluating-flags-server-side).
![Keep configurations and PII secure image](/img/react-tutorial-pii-diagram.png) ![Keep configurations and PII secure image](/img/react-tutorial-pii-diagram.png)

View File

@ -50,7 +50,7 @@ a. Limit PII (personally identifiable information) leakage from the end-user dev
b. Avoid leakage of configuration information from the central feature flag control service to end-user devices. b. Avoid leakage of configuration information from the central feature flag control service to end-user devices.
Solving both means you need to avoid evaluating feature flags on the user's machine due to security risks like exposing API keys and flag data. Instead, send application context (e.g. username, location, etc) to your feature flag evaluation service to evaluate the results. These results (and only these results) should be stored in the client-side application memory. By keeping the evaluated results for a specific context in memory, you avoid network roundtrips every time your application needs to check the status of a feature flag. This method prevents unauthorized access and data breaches by [keeping configurations and PII secure](/topics/feature-flags/never-expose-pii). Solving both means you need to avoid evaluating feature flags on the user's machine due to security risks like exposing API keys and flag data. Instead, send application context (e.g. username, location, etc) to your feature flag evaluation service to evaluate the results. These results (and only these results) should be stored in the client-side application memory. By keeping the evaluated results for a specific context in memory, you avoid network roundtrips every time your application needs to check the status of a feature flag. This method prevents unauthorized access and data breaches by [keeping configurations and PII secure](/topics/feature-flags/feature-flag-best-practices#2-protect-pii-by-evaluating-flags-server-side).
![Keep configurations and PII secure image](/img/react-tutorial-pii-diagram.png) ![Keep configurations and PII secure image](/img/react-tutorial-pii-diagram.png)

View File

@ -1,7 +1,10 @@
--- ---
title: Environment Import & Export title: Environment Import & Export
--- ---
import VideoContent from '@site/src/components/VideoContent.jsx' import VideoContent from '@site/src/components/VideoContent.jsx'
import Figure from '@site/src/components/Figure/Figure.tsx'
:::note Availability :::note Availability

View File

@ -71,7 +71,7 @@ Marking a flag as stale helps you deprecate a feature flag without removing the
You can use this to signal to your team to stop using the feature in your applications. Stale flags will show as stale in the [technical debt dashboard](./technical-debt). You can use this to signal to your team to stop using the feature in your applications. Stale flags will show as stale in the [technical debt dashboard](./technical-debt).
Marking a flag as stale generates the `feature-stale-on` [event](./reference/events#feature-stale-on). You can use [an integration](/integrations/integrations) to trigger automated workflows, such as posting notifications in a Slack channel, breaking project builds if the code contains stale flags, or automatically opening pull requests to remove stale flags from the code. Marking a flag as stale generates the `feature-stale-on` [event](/reference/events#feature-stale-on). You can use [an integration](/reference/integrations) to trigger automated workflows, such as posting notifications in a Slack channel, breaking project builds if the code contains stale flags, or automatically opening pull requests to remove stale flags from the code.
### Configure expected lifetime ### Configure expected lifetime

View File

@ -70,7 +70,7 @@ server configured for a specific Jira project.
![A table marked Unleash Server Configuration, listing Unleash server instances.](/img/jira_server_manage_servers.png) ![A table marked Unleash Server Configuration, listing Unleash server instances.](/img/jira_server_manage_servers.png)
Once you have configured at least one Unleash server, your users should be ready to [use the Jira Server plugin](/integrations/jira_server_plugin_usage) Once you have configured at least one Unleash server, your users should be ready to [use the Jira Server plugin](/reference/integrations/jira-server-plugin-usage)
### Edit existing servers ### Edit existing servers

View File

@ -77,14 +77,7 @@ The `PROMETHEUS_API` environment variable should point to the base path of the P
This setup means that there is a mutual dependency between Unleash and Prometheus, where Prometheus regularly fetches data from Unleash's backstage API and Unleash fetches and displays this data when you use the network view. This diagram provides a visual representation of that. This setup means that there is a mutual dependency between Unleash and Prometheus, where Prometheus regularly fetches data from Unleash's backstage API and Unleash fetches and displays this data when you use the network view. This diagram provides a visual representation of that.
```mermaid ![](/img/network-view.png)
sequenceDiagram
participant Unleash
loop Scrape data
Prometheus-->>Unleash: fetch internal-backstage/prometheus
end
Unleash->>+Prometheus: Query data for network view
```
[^1]: For instance: when using Unleash in an API setting, a common mistake is to instantiate a new SDK for every request instead of sharing a single instance across requests. This would be visible in the network overview graph as a large number of requests from the same app. [^1]: For instance: when using Unleash in an API setting, a common mistake is to instantiate a new SDK for every request instead of sharing a single instance across requests. This would be visible in the network overview graph as a large number of requests from the same app.

View File

@ -55,7 +55,6 @@ If you see an item marked with a ❌ that you would find useful, feel free to re
::: :::
<!-- prettier-ignore-start -->
| Capability | [Java](/docs/generated/sdks/server-side/java.md) | [Node.js](/docs/generated/sdks/server-side/node.md) | [Go](/docs/generated/sdks/server-side/go.md) | [Python](/docs/generated/sdks/server-side/python.md) | [Ruby](/docs/generated/sdks/server-side/ruby.md) | [.NET](/docs/generated/sdks/server-side/dotnet.md) | [PHP](/docs/generated/sdks/server-side/php.md) | [Rust](/docs/generated/sdks/server-side/rust.md) | | Capability | [Java](/docs/generated/sdks/server-side/java.md) | [Node.js](/docs/generated/sdks/server-side/node.md) | [Go](/docs/generated/sdks/server-side/go.md) | [Python](/docs/generated/sdks/server-side/python.md) | [Ruby](/docs/generated/sdks/server-side/ruby.md) | [.NET](/docs/generated/sdks/server-side/dotnet.md) | [PHP](/docs/generated/sdks/server-side/php.md) | [Rust](/docs/generated/sdks/server-side/rust.md) |
| --- | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | | --- | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
@ -89,7 +88,7 @@ If you see an item marked with a ❌ that you would find useful, feel free to re
| Static fields (`environment`, `appName`) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Static fields (`environment`, `appName`) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Defined fields | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Defined fields | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Custom properties | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Custom properties | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| **Category: [`isEnabled`](./client-specification#implementation-of-isenabled)** | | | | | | | | | | **Category: [`isEnabled`](/client-specification#implementation-of-isenabled)** | | | | | | | | |
| Can take context | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Can take context | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Override fallback value | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Override fallback value | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Fallback function | ✅ | ✅ | ✅ | ✅ | ✅ | ⭕ | ⭕ | ⭕ | | Fallback function | ✅ | ✅ | ✅ | ✅ | ✅ | ⭕ | ⭕ | ⭕ |
@ -110,7 +109,6 @@ If you see an item marked with a ❌ that you would find useful, feel free to re
| Bootstrap from file | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ⭕ | | Bootstrap from file | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ⭕ |
| Custom Bootstrap implementation | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ⭕ | | Custom Bootstrap implementation | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ⭕ |
<!-- prettier-ignore-end -->
## Community SDKs ❤️ {#community-sdks} ## Community SDKs ❤️ {#community-sdks}
@ -138,7 +136,7 @@ Here's some of the fantastic work our community has done to make Unleash work in
If you can't find an SDK that fits your requirements, you can also develop your own SDK. To make implementation easier, check out these resources: If you can't find an SDK that fits your requirements, you can also develop your own SDK. To make implementation easier, check out these resources:
- [Unleash Client Specifications](https://github.com/Unleash/client-specification) - Used by all official SDKs to make sure they behave correctly across different language implementations. This lets us verify that a gradual rollout to 10% of the users would affect the same users regardless of which SDK you're using. - [Unleash Client Specifications](https://github.com/Unleash/client-specification) - Used by all official SDKs to make sure they behave correctly across different language implementations. This lets us verify that a gradual rollout to 10% of the users would affect the same users regardless of which SDK you're using.
- [Client SDK overview](./client-specification) - A brief, overall guide of the _Unleash Architecture_ and important aspects of the SDK role in it all. - [Client SDK overview](/client-specification) - A brief, overall guide of the _Unleash Architecture_ and important aspects of the SDK role in it all.
## Client-side SDK behavior ## Client-side SDK behavior

View File

@ -52,7 +52,7 @@ In theory, you could create segments with a thousand constraints, each with a mi
By default, you can apply **at most 5 segments to any one strategy**. Separate strategies (even on the same feature) do not count towards the same total, so you can have two strategies with 5 segments each. By default, you can apply **at most 5 segments to any one strategy**. Separate strategies (even on the same feature) do not count towards the same total, so you can have two strategies with 5 segments each.
You **can** [configure segment limits](./using-unleash/deploy/configuring-unleash#segments) with environment variables. You **can** [configure segment limits](/using-unleash/deploy/configuring-unleash#segments) with environment variables.
### A note on large segments {#large-segments} ### A note on large segments {#large-segments}

View File

@ -23,7 +23,7 @@ Before you can connect your application to Unleash you need a Unleash server. Yo
![A visual overview of an Unleash system as described in the following paragraph.](/img/unleash-architecture-edge.png 'System Overview') ![A visual overview of an Unleash system as described in the following paragraph.](/img/unleash-architecture-edge.png 'System Overview')
- [**Unleash API**](/reference/api/unleash) - The Unleash instance. This is where you create feature flags, configure activation strategies, and parameters, etc. The service that contains all feature flags and their configurations. Configurations declare which activation strategies to use and which parameters they should get. - [**Unleash API**](/reference/api/unleash) - The Unleash instance. This is where you create feature flags, configure activation strategies, and parameters, etc. The service that contains all feature flags and their configurations. Configurations declare which activation strategies to use and which parameters they should get.
- **Unleash Admin UI** - The bundled web interface for interacting with the Unleash instance. Manage flags, define strategies, look at metrics, and much more. Use the UI to [create feature flags](/how-to-create-feature-flag), [manage project access roles](../how-to/how-to-create-and-assign-custom-project-roles), [create API tokens](how-to/how-to-create-api-tokens), and more. - **Unleash Admin UI** - The bundled web interface for interacting with the Unleash instance. Manage flags, define strategies, look at metrics, and much more. Use the UI to [create feature flags](/how-to-create-feature-flag), [manage project access roles](../how-to/how-to-create-and-assign-custom-project-roles), [create API tokens](../how-to/how-to-create-api-tokens), and more.
- [**Unleash SDKs**](../reference/sdks) - Unleash SDKs integrate into your applications and get feature configurations from the Unleash API. Use them to check whether features are enabled or disabled and to send metrics to the Unleash API. [See all our SDKs](../reference/sdks) - [**Unleash SDKs**](../reference/sdks) - Unleash SDKs integrate into your applications and get feature configurations from the Unleash API. Use them to check whether features are enabled or disabled and to send metrics to the Unleash API. [See all our SDKs](../reference/sdks)
- [**Unleash Edge**](../reference/unleash-edge) - The Unleash Edge sits between front-end and native applications on one side and the Unleash API on the other. It can also sit between server-side SDKs and the Unleash API as well. You can scale it independently of the Unleash API to handle large request rates without causing issues for the Unleash API. Edge has all endpoints for the client API, frontend API, and proxy API. - [**Unleash Edge**](../reference/unleash-edge) - The Unleash Edge sits between front-end and native applications on one side and the Unleash API on the other. It can also sit between server-side SDKs and the Unleash API as well. You can scale it independently of the Unleash API to handle large request rates without causing issues for the Unleash API. Edge has all endpoints for the client API, frontend API, and proxy API.

View File

@ -144,8 +144,6 @@ As such, if you're relying on the specifics of the error structure for those API
Before you upgrade we strongly recommend that you take a full [database backup](database-backup), to make sure you can downgrade to version 3. Before you upgrade we strongly recommend that you take a full [database backup](database-backup), to make sure you can downgrade to version 3.
You can also read the highlights of **[what's new in v4](/user_guide/v4-whats-new)**.
### 1. All API calls now require a token. {#1-all-api-calls-now-requires-token} ### 1. All API calls now require a token. {#1-all-api-calls-now-requires-token}
If you are upgrading from Unleash Open-Source v3 client SDKs did not need to use an API token in order to connect to Unleash-server. Starting from v4 we have back-ported the API token handling for Enterprise in to the Open-Source version. This means that all client SDKs now need to use a client token in order to connect to Unleash. If you are upgrading from Unleash Open-Source v3 client SDKs did not need to use an API token in order to connect to Unleash-server. Starting from v4 we have back-ported the API token handling for Enterprise in to the Open-Source version. This means that all client SDKs now need to use a client token in order to connect to Unleash.

View File

@ -1,5 +1,8 @@
const { sdks } = require('./remote-content/sdks'); import type { Config } from '@docusaurus/types';
const { docs: edgeAndProxy } = require('./remote-content/edge-proxy');
import { sdks } from './remote-content/sdks';
import { docs as edgeAndProxy } from './remote-content/edge-proxy';
import pluginNpm2Yarn from '@docusaurus/remark-plugin-npm2yarn';
// for a given redirect object, modify it's `from` property such that for every // for a given redirect object, modify it's `from` property such that for every
// path that doesn't start with `/docs/`, a corresponding path that _does_ start // path that doesn't start with `/docs/`, a corresponding path that _does_ start
@ -38,8 +41,8 @@ const addDocsRoutePrefix = ({ from, ...rest }) => {
from: addDocs(from), from: addDocs(from),
}; };
}; };
/** @type {import('@docusaurus/types').DocusaurusConfig} */
module.exports = { const config: Config = {
title: 'Unleash Documentation', title: 'Unleash Documentation',
tagline: 'The enterprise ready feature flag service', tagline: 'The enterprise ready feature flag service',
url: 'https://docs.getunleash.io', url: 'https://docs.getunleash.io',
@ -50,7 +53,6 @@ module.exports = {
organizationName: 'Unleash', // Usually your GitHub org/user name. organizationName: 'Unleash', // Usually your GitHub org/user name.
projectName: 'unleash.github.io', // Usually your repo name. projectName: 'unleash.github.io', // Usually your repo name.
trailingSlash: false, trailingSlash: false,
markdown: { mermaid: true },
customFields: { customFields: {
// expose env vars etc here // expose env vars etc here
environment: process.env.NODE_ENV, environment: process.env.NODE_ENV,
@ -170,17 +172,13 @@ module.exports = {
], ],
}, },
prism: { prism: {
theme: require('prism-react-renderer/themes/oceanicNext'),
additionalLanguages: [ additionalLanguages: [
'csharp', 'csharp',
'dart', 'dart',
'http',
'java', 'java',
'kotlin',
'php', 'php',
'ruby', 'ruby',
'rust', 'bash',
'swift',
], ],
}, },
languageTabs: [ languageTabs: [
@ -290,22 +288,16 @@ module.exports = {
'@docusaurus/preset-classic', '@docusaurus/preset-classic',
{ {
docs: { docs: {
sidebarPath: require.resolve('./sidebars.js'),
// Please change this to your repo. // Please change this to your repo.
editUrl: editUrl:
'https://github.com/Unleash/unleash/edit/main/website/', 'https://github.com/Unleash/unleash/edit/main/website/',
routeBasePath: '/', routeBasePath: '/',
remarkPlugins: [ remarkPlugins: [[pluginNpm2Yarn, { sync: true }]],
[
require('@docusaurus/remark-plugin-npm2yarn'),
{ sync: true },
],
],
docLayoutComponent: '@theme/DocPage',
docItemComponent: '@theme/ApiItem', docItemComponent: '@theme/ApiItem',
sidebarPath: './sidebars.ts',
}, },
theme: { theme: {
customCss: require.resolve('./src/css/custom.css'), customCss: './src/css/custom.css',
}, },
googleAnalytics: { googleAnalytics: {
trackingID: 'UA-134882379-1', trackingID: 'UA-134882379-1',
@ -911,7 +903,6 @@ module.exports = {
], ],
themes: [ themes: [
'docusaurus-theme-openapi-docs', // Allows use of @theme/ApiItem and other components 'docusaurus-theme-openapi-docs', // Allows use of @theme/ApiItem and other components
'@docusaurus/theme-mermaid',
], ],
scripts: [ scripts: [
{ {
@ -924,5 +915,7 @@ module.exports = {
defer: true, defer: true,
}, },
], ],
clientModules: [require.resolve('./global.js')], clientModules: ['./global.js'],
}; };
export default config;

View File

@ -11,7 +11,7 @@
"build": "yarn generate && yarn fetch-remote-content && docusaurus build", "build": "yarn generate && yarn fetch-remote-content && docusaurus build",
"swizzle": "docusaurus swizzle", "swizzle": "docusaurus swizzle",
"fetch-remote-content": "docusaurus download-remote-content-external && docusaurus download-remote-content-sdks", "fetch-remote-content": "docusaurus download-remote-content-external && docusaurus download-remote-content-sdks",
"generate": "docusaurus gen-api-docs all && node clean-generated-docs.js", "generate": "docusaurus gen-api-docs all && node clean-generated-docs.mjs",
"deploy": "yarn generate && yarn fetch-remote-content && docusaurus deploy", "deploy": "yarn generate && yarn fetch-remote-content && docusaurus deploy",
"clear": "docusaurus clear", "clear": "docusaurus clear",
"serve": "docusaurus serve", "serve": "docusaurus serve",
@ -20,40 +20,22 @@
"test": "NODE_ENV=test node --trace-warnings ../node_modules/.bin/jest remote-content" "test": "NODE_ENV=test node --trace-warnings ../node_modules/.bin/jest remote-content"
}, },
"dependencies": { "dependencies": {
"@docusaurus/core": "2.3.1", "@docusaurus/core": "^3.5.2",
"@docusaurus/plugin-client-redirects": "2.3.1", "@docusaurus/plugin-client-redirects": "^3.5.2",
"@docusaurus/plugin-google-analytics": "2.3.1", "@docusaurus/plugin-google-analytics": "^3.5.2",
"@docusaurus/preset-classic": "2.3.1", "@docusaurus/preset-classic": "^3.5.2",
"@docusaurus/remark-plugin-npm2yarn": "2.3.1", "@docusaurus/remark-plugin-npm2yarn": "3.5.2",
"@docusaurus/theme-mermaid": "2.3.1", "@mdx-js/react": "^3.1.0",
"@mdx-js/react": "1.6.22", "docusaurus-plugin-openapi-docs": "^4.1.0",
"@svgr/webpack": "8.1.0", "docusaurus-plugin-remote-content": "^4.0.0",
"browserslist": "^4.16.5", "docusaurus-theme-openapi-docs": "^4.1.0",
"docusaurus-plugin-openapi-docs": "2.0.0-beta.3", "git-url-parse": "^15.0.0",
"docusaurus-plugin-remote-content": "^3.1.0",
"docusaurus-theme-openapi-docs": "2.0.0-beta.2",
"git-url-parse": "^14.0.0",
"plugin-image-zoom": "flexanalytics/plugin-image-zoom", "plugin-image-zoom": "flexanalytics/plugin-image-zoom",
"prism-react-renderer": "^2.4.0",
"prism-svelte": "^0.5.0", "prism-svelte": "^0.5.0",
"react": "18.3.1", "react": "^18.3.1",
"react-dom": "18.3.1", "react-dom": "^18.3.1",
"url-loader": "4.1.1" "replace-in-file": "^8.2.0"
},
"resolutions": {
"axios": "^0.28.0",
"async": "^3.2.4",
"trim": "^1.0.0",
"got": "^13.0.0",
"glob-parent": "^6.0.0",
"browserslist": "^4.16.5",
"set-value": "^4.0.1",
"ansi-regex": "^5.0.1",
"nth-check": "^2.0.1",
"minimatch": "^5.0.0",
"decode-uri-component": "^0.4.0",
"qs": "^6.9.7",
"ws": "^8.18.0",
"semver": "^7.5.3"
}, },
"browserslist": { "browserslist": {
"production": [ "production": [
@ -68,14 +50,14 @@
] ]
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "7.25.8", "@docusaurus/module-type-aliases": "^3.5.2",
"@docusaurus/module-type-aliases": "2.3.1", "@docusaurus/types": "^3.5.2",
"@tsconfig/docusaurus": "2.0.3", "@tsconfig/docusaurus": "2.0.3",
"babel-loader": "9.2.1", "@types/react": "^18.3.12",
"enhanced-resolve": "5.17.1", "typescript": "5.6.3"
"react-router": "6.27.0", },
"replace-in-file": "7.2.0", "resolutions": {
"typescript": "5.4.5" "http-proxy-middleware": "3.0.3"
}, },
"packageManager": "yarn@4.5.1" "packageManager": "yarn@4.5.1"
} }

View File

@ -1,10 +1,10 @@
const { import {
enrich, enrich,
mapObject, mapObject,
modifyContent, modifyContent,
getRepoData, getRepoData,
getUrls, getUrls,
} = require('./shared'); } from './shared';
const DOCS = mapObject(enrich)({ const DOCS = mapObject(enrich)({
'unleash-proxy': { 'unleash-proxy': {
@ -46,7 +46,7 @@ const modifyContent2 = modifyContent({
getAdditionalAdmonitions: getAdmonitions, getAdditionalAdmonitions: getAdmonitions,
}); });
module.exports.docs = { export const docs = {
urls: getUrls(DOCS), urls: getUrls(DOCS),
modifyContent: modifyContent2, modifyContent: modifyContent2,
}; };

View File

@ -1,9 +1,9 @@
const { import {
enrichAdditional, enrichAdditional,
modifyContent, modifyContent,
getRepoData, getRepoData,
getUrls, getUrls,
} = require('./shared'); } from './shared';
// Type definitions // Type definitions
// //
@ -117,7 +117,7 @@ const modifyContent2 = modifyContent({
getAdditionalAdmonitions: getAdmonitions, getAdditionalAdmonitions: getAdmonitions,
}); });
module.exports.sdks = { export const sdks = {
urls: getUrls(SDKS), urls: getUrls(SDKS),
modifyContent: modifyContent2, modifyContent: modifyContent2,
}; };

View File

@ -1,4 +1,4 @@
const { docs } = require('./edge-proxy'); import { docs } from './edge-proxy';
test('Should get all sub pages', () => { test('Should get all sub pages', () => {
expect(docs.urls).toStrictEqual([ expect(docs.urls).toStrictEqual([

View File

@ -1,9 +1,9 @@
const path = require('path'); import path from 'node:path';
module.exports.mapObject = (fn) => (o) => export const mapObject = (fn) => (o) =>
Object.fromEntries(Object.entries(o).map(fn)); Object.fromEntries(Object.entries(o).map(fn));
module.exports.enrichAdditional = export const enrichAdditional =
(additionalProperties) => (additionalProperties) =>
([repoName, repoData]) => { ([repoName, repoData]) => {
const repoUrl = `https://github.com/Unleash/${repoName}`; const repoUrl = `https://github.com/Unleash/${repoName}`;
@ -17,9 +17,10 @@ module.exports.enrichAdditional =
{ ...repoData, repoUrl, slugName, branch, ...additionalProperties }, { ...repoData, repoUrl, slugName, branch, ...additionalProperties },
]; ];
}; };
module.exports.enrich = module.exports.enrichAdditional({});
module.exports.getRepoData = (documents) => (filename) => { export const enrich = enrichAdditional({});
export const getRepoData = (documents) => (filename) => {
const repoName = filename.split('/')[0]; const repoName = filename.split('/')[0];
const repoData = documents[repoName]; const repoData = documents[repoName];
@ -80,7 +81,7 @@ const replaceLinks = ({ content, repo }) => {
.replaceAll(imageSrcLink, replaceImageSrcLink); .replaceAll(imageSrcLink, replaceImageSrcLink);
}; };
module.exports.modifyContent = export const modifyContent =
({ ({
getRepoDataFn, getRepoDataFn,
filePath = () => {}, filePath = () => {},
@ -128,11 +129,15 @@ module.exports.modifyContent =
content: `--- content: `---
title: ${subpage?.sidebarName ?? data.sidebarName} title: ${subpage?.sidebarName ?? data.sidebarName}
slug: ${processedSlug} slug: ${processedSlug}
custom_edit_url: ${data.repoUrl}/edit/${data.branch}/${subpage ? subpageKey : 'README.md'} custom_edit_url: ${data.repoUrl}/edit/${data.branch}/${
subpage ? subpageKey : 'README.md'
}
--- ---
:::info Generated content :::info Generated content
This document was generated from ${subpage ? subpageKey : 'README.md'} in the [${data.sidebarName} GitHub repository](${data.repoUrl}). This document was generated from ${
subpage ? subpageKey : 'README.md'
} in the [${data.sidebarName} GitHub repository](${data.repoUrl}).
::: :::
${additionalAdmonitions} ${additionalAdmonitions}
@ -152,7 +157,7 @@ This content was generated on <time dateTime="${generationTime.toISOString()}">$
}; };
}; };
module.exports.getUrls = (documents) => export const getUrls = (documents) =>
Object.entries(documents).flatMap(([repo, { branch, subPages }]) => [ Object.entries(documents).flatMap(([repo, { branch, subPages }]) => [
`${repo}/${branch}/README.md`, `${repo}/${branch}/README.md`,
...(Object.keys(subPages ?? {}).map( ...(Object.keys(subPages ?? {}).map(

View File

@ -9,10 +9,11 @@
Create as many sidebars as you want. Create as many sidebars as you want.
*/ */
// TODO: Add warning to legacy API docs - but generated items import type { SidebarsConfig } from '@docusaurus/plugin-content-docs';
// TODO: Continue to clean URLs & redirects - but wait for SEO results first
module.exports = { import docsSidebar from './docs/reference/api/unleash/sidebar.ts';
const sidebars: SidebarsConfig = {
academy: [ academy: [
{ {
label: 'Unleash Academy', label: 'Unleash Academy',
@ -237,7 +238,7 @@ module.exports = {
label: 'iOS', label: 'iOS',
link: { link: {
type: 'doc', type: 'doc',
id: 'feature-flag-tutorials/ios/implementing-feature-flags', id: 'feature-flag-tutorials/ios/implementing-feature-flags-ios',
}, },
items: [ items: [
{ {
@ -381,7 +382,7 @@ module.exports = {
slug: '/reference/api/unleash', slug: '/reference/api/unleash',
}, },
items: [ items: [
require('./docs/reference/api/unleash/sidebar.js'), docsSidebar,
{ {
'System API': [ 'System API': [
'reference/api/legacy/unleash/internal/prometheus', 'reference/api/legacy/unleash/internal/prometheus',
@ -686,3 +687,5 @@ module.exports = {
}, },
], ],
}; };
export default sidebars;

View File

@ -1,7 +1,7 @@
// biome-ignore lint/correctness/noUnusedImports: Needs this for React to work // biome-ignore lint/correctness/noUnusedImports: Needs this for React to work
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { getContributors } from './contributors'; import { getContributors } from './contributors';
import styles from './contributors.module.scss'; import styles from './contributors.module.css';
const unleashTeam = new Map([ const unleashTeam = new Map([
['alvinometric', 'developer advocate, Unleash'], ['alvinometric', 'developer advocate, Unleash'],

View File

@ -8,10 +8,10 @@
gap: 20px; gap: 20px;
margin: 0; margin: 0;
padding: 0; padding: 0;
li{
list-style: none;
} }
.wrapper li {
list-style: none;
} }
.unleash { .unleash {
@ -33,8 +33,9 @@
.contributor { .contributor {
margin-top: 10px; margin-top: 10px;
}
img{ .contributor img {
border-radius: 100%; border-radius: 100%;
margin: 0; margin: 0;
padding: 0; padding: 0;
@ -42,7 +43,6 @@
transition: border-color var(--ifm-transition-fast) var(--ifm-transition-timing-default), transition: border-color var(--ifm-transition-fast) var(--ifm-transition-timing-default),
scale var(--ifm-transition-fast) var(--ifm-transition-timing-default); scale var(--ifm-transition-fast) var(--ifm-transition-timing-default);
} }
}
.contributor img:hover { .contributor img:hover {
border-color: var(--ifm-pagination-nav-color-hover); border-color: var(--ifm-pagination-nav-color-hover);

View File

@ -1,7 +1,7 @@
// biome-ignore lint/correctness/noUnusedImports: Needs this for React to work // biome-ignore lint/correctness/noUnusedImports: Needs this for React to work
import React from 'react'; import React from 'react';
import Footer from '@theme-original/DocItem/Footer'; import Footer from '@theme-original/DocItem/Footer';
import { useDoc } from '@docusaurus/theme-common/internal'; import { useDoc } from '@docusaurus/plugin-content-docs/client';
import GitHubContributors from './GitHubContributors'; import GitHubContributors from './GitHubContributors';
import GitUrlParse from 'git-url-parse'; import GitUrlParse from 'git-url-parse';

View File

@ -1,9 +1,15 @@
import siteConfig from '@generated/docusaurus.config'; import siteConfig from '@generated/docusaurus.config';
export default function prismIncludeLanguages(PrismObject) { import type * as PrismNamespace from 'prismjs';
import type { Optional } from 'utility-types';
export default function prismIncludeLanguages(
PrismObject: typeof PrismNamespace,
): void {
const { const {
themeConfig: { prism }, themeConfig: { prism },
} = siteConfig; } = siteConfig;
const { additionalLanguages } = prism; const { additionalLanguages } = prism as { additionalLanguages: string[] };
// Prism components work on the Prism instance on the window, while prism- // Prism components work on the Prism instance on the window, while prism-
// react-renderer uses its own Prism instance. We temporarily mount the // react-renderer uses its own Prism instance. We temporarily mount the
// instance onto window, import components to enhance it, then remove it to // instance onto window, import components to enhance it, then remove it to
@ -11,12 +17,17 @@ export default function prismIncludeLanguages(PrismObject) {
// You can mutate PrismObject: registering plugins, deleting languages... As // You can mutate PrismObject: registering plugins, deleting languages... As
// long as you don't re-assign it // long as you don't re-assign it
globalThis.Prism = PrismObject; globalThis.Prism = PrismObject;
additionalLanguages.forEach((lang) => { additionalLanguages.forEach((lang) => {
if (lang === 'php') {
// eslint-disable-next-line global-require
require('prismjs/components/prism-markup-templating.js');
}
// eslint-disable-next-line global-require, import/no-dynamic-require // eslint-disable-next-line global-require, import/no-dynamic-require
require(`prismjs/components/prism-${lang}`); require(`prismjs/components/prism-${lang}`);
}); });
require('prism-svelte'); require('prism-svelte');
delete globalThis.Prism; delete (globalThis as Optional<typeof globalThis, 'Prism'>).Prism;
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

File diff suppressed because it is too large Load Diff

314
yarn.lock
View File

@ -104,13 +104,14 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@babel/code-frame@npm:^7.25.7": "@babel/code-frame@npm:^7.25.9":
version: 7.25.7 version: 7.26.0
resolution: "@babel/code-frame@npm:7.25.7" resolution: "@babel/code-frame@npm:7.26.0"
dependencies: dependencies:
"@babel/highlight": "npm:^7.25.7" "@babel/helper-validator-identifier": "npm:^7.25.9"
js-tokens: "npm:^4.0.0"
picocolors: "npm:^1.0.0" picocolors: "npm:^1.0.0"
checksum: 10c0/14825c298bdec914caf3d24d1383b6d4cd6b030714686004992f4fc251831ecf432236652896f99d5d341f17170ae9a07b58d8d7b15aa0df8cfa1c5a7d5474bc checksum: 10c0/46f7e367714be736b52ea3c01b24f47e2102e210fb83021d1c8237d8fc511b9538909e16e2fcdbb5cb6173e0794e28624309a59014e52fcfb7bde908f5284388
languageName: node languageName: node
linkType: hard linkType: hard
@ -121,33 +122,33 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@babel/compat-data@npm:^7.25.7": "@babel/compat-data@npm:^7.25.9":
version: 7.25.8 version: 7.26.0
resolution: "@babel/compat-data@npm:7.25.8" resolution: "@babel/compat-data@npm:7.26.0"
checksum: 10c0/8b81c17580e5fb4cbb6a3c52079f8c283fc59c0c6bd2fe14cfcf9c44b32d2eaab71b02c5633e2c679f5896f73f8ac4036ba2e67a4c806e8f428e4b11f526d7f4 checksum: 10c0/6325c9151a3c9b0a3a807e854a26255ef66d989bff331475a935af9bb18f160e0fffe6aed550e4e96b63f91efcd874bfbaab2a1f4a2f8d25645d712a0de590fb
languageName: node languageName: node
linkType: hard linkType: hard
"@babel/core@npm:7.25.8": "@babel/core@npm:7.25.9":
version: 7.25.8 version: 7.25.9
resolution: "@babel/core@npm:7.25.8" resolution: "@babel/core@npm:7.25.9"
dependencies: dependencies:
"@ampproject/remapping": "npm:^2.2.0" "@ampproject/remapping": "npm:^2.2.0"
"@babel/code-frame": "npm:^7.25.7" "@babel/code-frame": "npm:^7.25.9"
"@babel/generator": "npm:^7.25.7" "@babel/generator": "npm:^7.25.9"
"@babel/helper-compilation-targets": "npm:^7.25.7" "@babel/helper-compilation-targets": "npm:^7.25.9"
"@babel/helper-module-transforms": "npm:^7.25.7" "@babel/helper-module-transforms": "npm:^7.25.9"
"@babel/helpers": "npm:^7.25.7" "@babel/helpers": "npm:^7.25.9"
"@babel/parser": "npm:^7.25.8" "@babel/parser": "npm:^7.25.9"
"@babel/template": "npm:^7.25.7" "@babel/template": "npm:^7.25.9"
"@babel/traverse": "npm:^7.25.7" "@babel/traverse": "npm:^7.25.9"
"@babel/types": "npm:^7.25.8" "@babel/types": "npm:^7.25.9"
convert-source-map: "npm:^2.0.0" convert-source-map: "npm:^2.0.0"
debug: "npm:^4.1.0" debug: "npm:^4.1.0"
gensync: "npm:^1.0.0-beta.2" gensync: "npm:^1.0.0-beta.2"
json5: "npm:^2.2.3" json5: "npm:^2.2.3"
semver: "npm:^6.3.1" semver: "npm:^6.3.1"
checksum: 10c0/8411ea506e6f7c8a39ab5c1524b00589fa3b087edb47389708f7fe07170929192171734666e3ea10b95a951643a531a6d09eedfe071572c9ea28516646265086 checksum: 10c0/40d3064ebe906f65ed4153a0f4d75c679a19e4d71e425035b7bbe2d292a9167274f1a0d908d4d6c8f484fcddeb10bd91e0c7878fdb3dfad1bb00f6a319ce431d
languageName: node languageName: node
linkType: hard linkType: hard
@ -197,15 +198,16 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@babel/generator@npm:^7.25.7": "@babel/generator@npm:^7.25.9":
version: 7.25.7 version: 7.26.0
resolution: "@babel/generator@npm:7.25.7" resolution: "@babel/generator@npm:7.26.0"
dependencies: dependencies:
"@babel/types": "npm:^7.25.7" "@babel/parser": "npm:^7.26.0"
"@babel/types": "npm:^7.26.0"
"@jridgewell/gen-mapping": "npm:^0.3.5" "@jridgewell/gen-mapping": "npm:^0.3.5"
"@jridgewell/trace-mapping": "npm:^0.3.25" "@jridgewell/trace-mapping": "npm:^0.3.25"
jsesc: "npm:^3.0.2" jsesc: "npm:^3.0.2"
checksum: 10c0/c03a26c79864d60d04ce36b649c3fa0d6fd7b2bf6a22e22854a0457aa09206508392dd73ee40e7bc8d50b3602f9ff068afa47770cda091d332e7db1ca382ee96 checksum: 10c0/b6bb9185f19a97eaf58e04a6d39a13237076678e7ed16b6321dea914535d4bf6a8d7727c9dcb65539845aa0096b326eb67be4bab764bd74bcfd848e2eda68609
languageName: node languageName: node
linkType: hard linkType: hard
@ -224,16 +226,16 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@babel/helper-compilation-targets@npm:^7.25.7": "@babel/helper-compilation-targets@npm:^7.25.9":
version: 7.25.7 version: 7.25.9
resolution: "@babel/helper-compilation-targets@npm:7.25.7" resolution: "@babel/helper-compilation-targets@npm:7.25.9"
dependencies: dependencies:
"@babel/compat-data": "npm:^7.25.7" "@babel/compat-data": "npm:^7.25.9"
"@babel/helper-validator-option": "npm:^7.25.7" "@babel/helper-validator-option": "npm:^7.25.9"
browserslist: "npm:^4.24.0" browserslist: "npm:^4.24.0"
lru-cache: "npm:^5.1.1" lru-cache: "npm:^5.1.1"
semver: "npm:^6.3.1" semver: "npm:^6.3.1"
checksum: 10c0/705be7e5274a3fdade68e3e2cf42e2b600316ab52794e13b91299a16f16c926f15886b6e9d6df20eb943ccc1cdba5a363d4766f8d01e47b8e6f4e01175f5e66c checksum: 10c0/a6b26a1e4222e69ef8e62ee19374308f060b007828bc11c65025ecc9e814aba21ff2175d6d3f8bf53c863edd728ee8f94ba7870f8f90a37d39552ad9933a8aaa
languageName: node languageName: node
linkType: hard linkType: hard
@ -279,13 +281,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@babel/helper-module-imports@npm:^7.25.7": "@babel/helper-module-imports@npm:^7.25.9":
version: 7.25.7 version: 7.25.9
resolution: "@babel/helper-module-imports@npm:7.25.7" resolution: "@babel/helper-module-imports@npm:7.25.9"
dependencies: dependencies:
"@babel/traverse": "npm:^7.25.7" "@babel/traverse": "npm:^7.25.9"
"@babel/types": "npm:^7.25.7" "@babel/types": "npm:^7.25.9"
checksum: 10c0/0fd0c3673835e5bf75558e184bcadc47c1f6dd2fe2016d53ebe1e5a6ae931a44e093015c2f9a6651c1a89f25c76d9246710c2b0b460b95ee069c464f2837fa2c checksum: 10c0/078d3c2b45d1f97ffe6bb47f61961be4785d2342a4156d8b42c92ee4e1b7b9e365655dd6cb25329e8fe1a675c91eeac7e3d04f0c518b67e417e29d6e27b6aa70
languageName: node languageName: node
linkType: hard linkType: hard
@ -305,17 +307,16 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@babel/helper-module-transforms@npm:^7.25.7": "@babel/helper-module-transforms@npm:^7.25.9":
version: 7.25.7 version: 7.26.0
resolution: "@babel/helper-module-transforms@npm:7.25.7" resolution: "@babel/helper-module-transforms@npm:7.26.0"
dependencies: dependencies:
"@babel/helper-module-imports": "npm:^7.25.7" "@babel/helper-module-imports": "npm:^7.25.9"
"@babel/helper-simple-access": "npm:^7.25.7" "@babel/helper-validator-identifier": "npm:^7.25.9"
"@babel/helper-validator-identifier": "npm:^7.25.7" "@babel/traverse": "npm:^7.25.9"
"@babel/traverse": "npm:^7.25.7"
peerDependencies: peerDependencies:
"@babel/core": ^7.0.0 "@babel/core": ^7.0.0
checksum: 10c0/f37fa7d1d4df21690535b278468cbd5faf0133a3080f282000cfa4f3ffc9462a1458f866b04b6a2f2d1eec4691236cba9a867da61270dab3ab19846e62f05090 checksum: 10c0/ee111b68a5933481d76633dad9cdab30c41df4479f0e5e1cc4756dc9447c1afd2c9473b5ba006362e35b17f4ebddd5fca090233bef8dfc84dca9d9127e56ec3a
languageName: node languageName: node
linkType: hard linkType: hard
@ -335,16 +336,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@babel/helper-simple-access@npm:^7.25.7":
version: 7.25.7
resolution: "@babel/helper-simple-access@npm:7.25.7"
dependencies:
"@babel/traverse": "npm:^7.25.7"
"@babel/types": "npm:^7.25.7"
checksum: 10c0/eed1b499bfb4f613c18debd61517e3de77b6da2727ca025aa05ac81599e0269f1dddb5237db04e8bb598115d015874752e0a7f11ff38672d74a4976097417059
languageName: node
linkType: hard
"@babel/helper-split-export-declaration@npm:^7.18.6": "@babel/helper-split-export-declaration@npm:^7.18.6":
version: 7.18.6 version: 7.18.6
resolution: "@babel/helper-split-export-declaration@npm:7.18.6" resolution: "@babel/helper-split-export-declaration@npm:7.18.6"
@ -384,10 +375,10 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@babel/helper-string-parser@npm:^7.25.7": "@babel/helper-string-parser@npm:^7.25.9":
version: 7.25.7 version: 7.25.9
resolution: "@babel/helper-string-parser@npm:7.25.7" resolution: "@babel/helper-string-parser@npm:7.25.9"
checksum: 10c0/73ef2ceb81f8294678a0afe8ab0103729c0370cac2e830e0d5128b03be5f6a2635838af31d391d763e3c5a4460ed96f42fd7c9b552130670d525be665913bc4c checksum: 10c0/7244b45d8e65f6b4338a6a68a8556f2cb161b782343e97281a5f2b9b93e420cad0d9f5773a59d79f61d0c448913d06f6a2358a87f2e203cf112e3c5b53522ee6
languageName: node languageName: node
linkType: hard linkType: hard
@ -426,10 +417,10 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@babel/helper-validator-identifier@npm:^7.25.7": "@babel/helper-validator-identifier@npm:^7.25.9":
version: 7.25.7 version: 7.25.9
resolution: "@babel/helper-validator-identifier@npm:7.25.7" resolution: "@babel/helper-validator-identifier@npm:7.25.9"
checksum: 10c0/07438e5bf01ab2882a15027fdf39ac3b0ba1b251774a5130917907014684e2f70fef8fd620137ca062c4c4eedc388508d2ea7a3a7d9936a32785f4fe116c68c0 checksum: 10c0/4fc6f830177b7b7e887ad3277ddb3b91d81e6c4a24151540d9d1023e8dc6b1c0505f0f0628ae653601eb4388a8db45c1c14b2c07a9173837aef7e4116456259d
languageName: node languageName: node
linkType: hard linkType: hard
@ -440,10 +431,10 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@babel/helper-validator-option@npm:^7.25.7": "@babel/helper-validator-option@npm:^7.25.9":
version: 7.25.7 version: 7.25.9
resolution: "@babel/helper-validator-option@npm:7.25.7" resolution: "@babel/helper-validator-option@npm:7.25.9"
checksum: 10c0/12ed418c8e3ed9ed44c8c80d823f4e42d399b5eb2e423adccb975e31a31a008cd3b5d8eab688b31f740caff4a1bb28fe06ea2fa7d635aee34cc0ad6995d50f0a checksum: 10c0/27fb195d14c7dcb07f14e58fe77c44eea19a6a40a74472ec05c441478fa0bb49fa1c32b2d64be7a38870ee48ef6601bdebe98d512f0253aea0b39756c4014f3e
languageName: node languageName: node
linkType: hard linkType: hard
@ -458,13 +449,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@babel/helpers@npm:^7.25.7": "@babel/helpers@npm:^7.25.9":
version: 7.25.7 version: 7.26.0
resolution: "@babel/helpers@npm:7.25.7" resolution: "@babel/helpers@npm:7.26.0"
dependencies: dependencies:
"@babel/template": "npm:^7.25.7" "@babel/template": "npm:^7.25.9"
"@babel/types": "npm:^7.25.7" "@babel/types": "npm:^7.26.0"
checksum: 10c0/3b3ae9e373bd785414195ef8f59976a69d5a6ebe0ef2165fdcc5165e5c3ee09e0fcee94bb457df2ddb8c0532e4146d0a9b7a96b3497399a4bff4ffe196b30228 checksum: 10c0/343333cced6946fe46617690a1d0789346960910225ce359021a88a60a65bc0d791f0c5d240c0ed46cf8cc63b5fd7df52734ff14e43b9c32feae2b61b1647097
languageName: node languageName: node
linkType: hard linkType: hard
@ -490,18 +481,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@babel/highlight@npm:^7.25.7":
version: 7.25.7
resolution: "@babel/highlight@npm:7.25.7"
dependencies:
"@babel/helper-validator-identifier": "npm:^7.25.7"
chalk: "npm:^2.4.2"
js-tokens: "npm:^4.0.0"
picocolors: "npm:^1.0.0"
checksum: 10c0/1f5894fdb0a0af6101fb2822369b2eeeae32cbeae2ef73ff73fc6a0a4a20471565cd9cfa589f54ed69df66adeca7c57266031ca9134b7bd244d023a488d419aa
languageName: node
linkType: hard
"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7": "@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7":
version: 7.20.7 version: 7.20.7
resolution: "@babel/parser@npm:7.20.7" resolution: "@babel/parser@npm:7.20.7"
@ -529,14 +508,14 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@babel/parser@npm:^7.25.7, @babel/parser@npm:^7.25.8": "@babel/parser@npm:^7.25.9, @babel/parser@npm:^7.26.0":
version: 7.25.8 version: 7.26.1
resolution: "@babel/parser@npm:7.25.8" resolution: "@babel/parser@npm:7.26.1"
dependencies: dependencies:
"@babel/types": "npm:^7.25.8" "@babel/types": "npm:^7.26.0"
bin: bin:
parser: ./bin/babel-parser.js parser: ./bin/babel-parser.js
checksum: 10c0/a1a13845b7e8dda4c970791814a4bbf60004969882f18f470e260ad822d2e1f8941948f851e9335895563610f240fa6c98481ce8019865e469502bbf21daafa4 checksum: 10c0/dc7d4e6b7eb667fa0784e7e2c3f6f92ca12ad72242f6d4311995310dae55093f02acdb595b69b0dbbf04cb61ad87156ac03186ff32eacfa35149c655bc22c14b
languageName: node languageName: node
linkType: hard linkType: hard
@ -734,14 +713,14 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@babel/template@npm:^7.25.7": "@babel/template@npm:^7.25.9":
version: 7.25.7 version: 7.25.9
resolution: "@babel/template@npm:7.25.7" resolution: "@babel/template@npm:7.25.9"
dependencies: dependencies:
"@babel/code-frame": "npm:^7.25.7" "@babel/code-frame": "npm:^7.25.9"
"@babel/parser": "npm:^7.25.7" "@babel/parser": "npm:^7.25.9"
"@babel/types": "npm:^7.25.7" "@babel/types": "npm:^7.25.9"
checksum: 10c0/8ae9e36e4330ee83d4832531d1d9bec7dc2ef6a2a8afa1ef1229506fd60667abcb17f306d1c3d7e582251270597022990c845d5d69e7add70a5aea66720decb9 checksum: 10c0/ebe677273f96a36c92cc15b7aa7b11cc8bc8a3bb7a01d55b2125baca8f19cae94ff3ce15f1b1880fb8437f3a690d9f89d4e91f16fc1dc4d3eb66226d128983ab
languageName: node languageName: node
linkType: hard linkType: hard
@ -763,18 +742,18 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@babel/traverse@npm:^7.25.7": "@babel/traverse@npm:^7.25.9":
version: 7.25.7 version: 7.25.9
resolution: "@babel/traverse@npm:7.25.7" resolution: "@babel/traverse@npm:7.25.9"
dependencies: dependencies:
"@babel/code-frame": "npm:^7.25.7" "@babel/code-frame": "npm:^7.25.9"
"@babel/generator": "npm:^7.25.7" "@babel/generator": "npm:^7.25.9"
"@babel/parser": "npm:^7.25.7" "@babel/parser": "npm:^7.25.9"
"@babel/template": "npm:^7.25.7" "@babel/template": "npm:^7.25.9"
"@babel/types": "npm:^7.25.7" "@babel/types": "npm:^7.25.9"
debug: "npm:^4.3.1" debug: "npm:^4.3.1"
globals: "npm:^11.1.0" globals: "npm:^11.1.0"
checksum: 10c0/75d73e52c507a7a7a4c7971d6bf4f8f26fdd094e0d3a0193d77edf6a5efa36fc3db91ec5cc48e8b94e6eb5d5ad21af0a1040e71309172851209415fd105efb1a checksum: 10c0/e90be586a714da4adb80e6cb6a3c5cfcaa9b28148abdafb065e34cc109676fc3db22cf98cd2b2fff66ffb9b50c0ef882cab0f466b6844be0f6c637b82719bba1
languageName: node languageName: node
linkType: hard linkType: hard
@ -822,14 +801,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@babel/types@npm:^7.25.7, @babel/types@npm:^7.25.8": "@babel/types@npm:^7.25.9, @babel/types@npm:^7.26.0":
version: 7.25.8 version: 7.26.0
resolution: "@babel/types@npm:7.25.8" resolution: "@babel/types@npm:7.26.0"
dependencies: dependencies:
"@babel/helper-string-parser": "npm:^7.25.7" "@babel/helper-string-parser": "npm:^7.25.9"
"@babel/helper-validator-identifier": "npm:^7.25.7" "@babel/helper-validator-identifier": "npm:^7.25.9"
to-fast-properties: "npm:^2.0.0" checksum: 10c0/b694f41ad1597127e16024d766c33a641508aad037abd08d0d1f73af753e1119fa03b4a107d04b5f92cc19c095a594660547ae9bead1db2299212d644b0a5cb8
checksum: 10c0/55ca2d6df6426c98db2769ce884ce5e9de83a512ea2dd7bcf56c811984dc14351cacf42932a723630c5afcff2455809323decd645820762182f10b7b5252b59f
languageName: node languageName: node
linkType: hard linkType: hard
@ -1555,8 +1533,8 @@ __metadata:
linkType: hard linkType: hard
"@slack/web-api@npm:^7.3.4": "@slack/web-api@npm:^7.3.4":
version: 7.5.0 version: 7.7.0
resolution: "@slack/web-api@npm:7.5.0" resolution: "@slack/web-api@npm:7.7.0"
dependencies: dependencies:
"@slack/logger": "npm:^4.0.0" "@slack/logger": "npm:^4.0.0"
"@slack/types": "npm:^2.9.0" "@slack/types": "npm:^2.9.0"
@ -1570,7 +1548,7 @@ __metadata:
p-queue: "npm:^6" p-queue: "npm:^6"
p-retry: "npm:^4" p-retry: "npm:^4"
retry: "npm:^0.13.1" retry: "npm:^0.13.1"
checksum: 10c0/067af68cb4aa823a13c328ae6db60ad22e41a97cdc2b69836176980a3075026c563f131b62f50ca9176481a0f6a4667e969fef783c63ea9cc1f206104fd20177 checksum: 10c0/1b1703206872ff106103440397aa37031ea862448f1c84ffc9c8efc71f8edc1b1ca129a18b7d2d3f7e9b0c7760052e1739a8165e407dc7b58e6140a8000cf7ff
languageName: node languageName: node
linkType: hard linkType: hard
@ -2061,12 +2039,12 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/node@npm:20.16.13": "@types/node@npm:20.16.14":
version: 20.16.13 version: 20.16.14
resolution: "@types/node@npm:20.16.13" resolution: "@types/node@npm:20.16.14"
dependencies: dependencies:
undici-types: "npm:~6.19.2" undici-types: "npm:~6.19.2"
checksum: 10c0/7f4fd7176db0802c62e11ebbf7a66d0248e2dc8ec9153d9fc8bcb164d9aed581d91c407046c823c522e60d0babfdc24a1618dba7f2c6920ef1a24e1d416c9550 checksum: 10c0/297da38ff6668ecd672b17a100b715166cab33bc8d586521fa28b2d2fb47b04475e1ad9f55e8a436c31d72c1fefa7bd4485a8ad66d2adc9b4515d8a28937e8b9
languageName: node languageName: node
linkType: hard linkType: hard
@ -2771,13 +2749,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"buffer-writer@npm:2.0.0":
version: 2.0.0
resolution: "buffer-writer@npm:2.0.0"
checksum: 10c0/c91b2ab09a200cf0862237e5a4dbd5077003b42d26d4f0c596ec7149f82ef83e0751d670bcdf379ed988d1a08c0fac7759a8cb928cf1a4710a1988a7618b1190
languageName: node
linkType: hard
"buildcheck@npm:~0.0.6": "buildcheck@npm:~0.0.6":
version: 0.0.6 version: 0.0.6
resolution: "buildcheck@npm:0.0.6" resolution: "buildcheck@npm:0.0.6"
@ -7246,13 +7217,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"packet-reader@npm:1.0.0":
version: 1.0.0
resolution: "packet-reader@npm:1.0.0"
checksum: 10c0/c86c3321bb07e0f03cc2db59f7701184e0bbfcb914f1fdc963993b03262486deb402292adcef39b64e3530ea66b3b2e2163d6da7b3792a730bdd1c6df3175aaa
languageName: node
linkType: hard
"parse-database-url@npm:^0.3.0, parse-database-url@npm:~0.3.0": "parse-database-url@npm:^0.3.0, parse-database-url@npm:~0.3.0":
version: 0.3.0 version: 0.3.0
resolution: "parse-database-url@npm:0.3.0" resolution: "parse-database-url@npm:0.3.0"
@ -7396,13 +7360,20 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"pg-connection-string@npm:^2.5.0, pg-connection-string@npm:^2.6.2, pg-connection-string@npm:^2.6.4": "pg-connection-string@npm:^2.5.0":
version: 2.6.4 version: 2.6.4
resolution: "pg-connection-string@npm:2.6.4" resolution: "pg-connection-string@npm:2.6.4"
checksum: 10c0/0d0b617df0fc6507bf6a94bdcd56c7a305788a1402d69bff9773350947c8f525d6d8136128065370749a3325e99658ae40fbdcce620fb8e60126181f0591a6a6 checksum: 10c0/0d0b617df0fc6507bf6a94bdcd56c7a305788a1402d69bff9773350947c8f525d6d8136128065370749a3325e99658ae40fbdcce620fb8e60126181f0591a6a6
languageName: node languageName: node
linkType: hard linkType: hard
"pg-connection-string@npm:^2.7.0":
version: 2.7.0
resolution: "pg-connection-string@npm:2.7.0"
checksum: 10c0/50a1496a1c858f9495d78a2c7a66d93ef3602e718aff2953bb5738f3ea616d7f727f32fc20513c9bed127650cd14c1ddc7b458396f4000e689d4b64c65c5c51e
languageName: node
linkType: hard
"pg-int8@npm:1.0.1": "pg-int8@npm:1.0.1":
version: 1.0.1 version: 1.0.1
resolution: "pg-int8@npm:1.0.1" resolution: "pg-int8@npm:1.0.1"
@ -7417,35 +7388,26 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"pg-pool@npm:^3.6.1": "pg-pool@npm:^3.7.0":
version: 3.6.1 version: 3.7.0
resolution: "pg-pool@npm:3.6.1" resolution: "pg-pool@npm:3.7.0"
peerDependencies: peerDependencies:
pg: ">=8.0" pg: ">=8.0"
checksum: 10c0/47837c4e4c2b9e195cec01bd58b6e276acc915537191707ad4d6ed975fd9bc03c73f63cb7fde4cb0e08ed059e35faf60fbd03744dee3af71d4b4631ab40eeb7f checksum: 10c0/9128673cf941f288c0cb1a74ca959a9b4f6075ef73b2cc7dece5d4db3dd7043784869e7c12bce2e69ca0df22132a419cc45c2050b4373632856fe8bae9eb94b5
languageName: node languageName: node
linkType: hard linkType: hard
"pg-pool@npm:^3.6.2": "pg-protocol@npm:*":
version: 3.6.2
resolution: "pg-pool@npm:3.6.2"
peerDependencies:
pg: ">=8.0"
checksum: 10c0/14c524549490954b5e48457a4b808df8f619f6deeb3b395b0cd184a8f4ed65a9273fe0697ba0341a41d6745af197f1437eb1cf51fff0cbbf5b0fb3852ebe5392
languageName: node
linkType: hard
"pg-protocol@npm:*, pg-protocol@npm:^1.6.0":
version: 1.6.0 version: 1.6.0
resolution: "pg-protocol@npm:1.6.0" resolution: "pg-protocol@npm:1.6.0"
checksum: 10c0/318a4d1e9cebd3927b10a8bc412f5017117a1f9a5fafb628d75847da7d1ab81c33250de58596bd0990029e14e92a995a851286d60fc236692299faf509572213 checksum: 10c0/318a4d1e9cebd3927b10a8bc412f5017117a1f9a5fafb628d75847da7d1ab81c33250de58596bd0990029e14e92a995a851286d60fc236692299faf509572213
languageName: node languageName: node
linkType: hard linkType: hard
"pg-protocol@npm:^1.6.1": "pg-protocol@npm:^1.7.0":
version: 1.6.1 version: 1.7.0
resolution: "pg-protocol@npm:1.6.1" resolution: "pg-protocol@npm:1.7.0"
checksum: 10c0/7eadef4010ac0a3925c460be7332ca4098a5c6d5181725a62193fcfa800000ae6632d98d814f3989b42cf5fdc3b45e34c714a1959d29174e81e30730e140ae5f checksum: 10c0/c4af854d9b843c808231c0040fed89f2b9101006157df8da2bb2f62a7dde702de748d852228dc22df41cc7ffddfb526af3bcb34b278b581e9f76a060789186c1
languageName: node languageName: node
linkType: hard linkType: hard
@ -7477,16 +7439,14 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"pg@npm:^8.11.2": "pg@npm:^8.11.2, pg@npm:^8.12.0":
version: 8.11.3 version: 8.13.1
resolution: "pg@npm:8.11.3" resolution: "pg@npm:8.13.1"
dependencies: dependencies:
buffer-writer: "npm:2.0.0"
packet-reader: "npm:1.0.0"
pg-cloudflare: "npm:^1.1.1" pg-cloudflare: "npm:^1.1.1"
pg-connection-string: "npm:^2.6.2" pg-connection-string: "npm:^2.7.0"
pg-pool: "npm:^3.6.1" pg-pool: "npm:^3.7.0"
pg-protocol: "npm:^1.6.0" pg-protocol: "npm:^1.7.0"
pg-types: "npm:^2.1.0" pg-types: "npm:^2.1.0"
pgpass: "npm:1.x" pgpass: "npm:1.x"
peerDependencies: peerDependencies:
@ -7497,29 +7457,7 @@ __metadata:
peerDependenciesMeta: peerDependenciesMeta:
pg-native: pg-native:
optional: true optional: true
checksum: 10c0/07e6967fc8bd5d72bab9be6620626e8e3ab59128ebf56bf0de83d67f10801a19221d88b3317e90b93339ba48d0498b39967b782ae39686aabda6bc647bceb438 checksum: 10c0/c13bc661cbdb115337bc8519254836faf4bd79106dfd7ed588c8ece8c8b2dd3b7376bfec9a9a2f7646fa095b0b310cec77a83c3ba2ea4872331446eb93fd9055
languageName: node
linkType: hard
"pg@npm:^8.12.0":
version: 8.12.0
resolution: "pg@npm:8.12.0"
dependencies:
pg-cloudflare: "npm:^1.1.1"
pg-connection-string: "npm:^2.6.4"
pg-pool: "npm:^3.6.2"
pg-protocol: "npm:^1.6.1"
pg-types: "npm:^2.1.0"
pgpass: "npm:1.x"
peerDependencies:
pg-native: ">=3.0.1"
dependenciesMeta:
pg-cloudflare:
optional: true
peerDependenciesMeta:
pg-native:
optional: true
checksum: 10c0/973e49b5e7327c42fc62806efa8c824159ab7a0b676cefe6eeb51a59b6e226587911ec27697f36c18d69e58a7f4f0b76d0829364087194d13ed431ab7c9c417a
languageName: node languageName: node
linkType: hard linkType: hard
@ -9340,7 +9278,7 @@ __metadata:
resolution: "unleash-server@workspace:." resolution: "unleash-server@workspace:."
dependencies: dependencies:
"@apidevtools/swagger-parser": "npm:10.1.0" "@apidevtools/swagger-parser": "npm:10.1.0"
"@babel/core": "npm:7.25.8" "@babel/core": "npm:7.25.9"
"@biomejs/biome": "npm:^1.8.3" "@biomejs/biome": "npm:^1.8.3"
"@cyclonedx/yarn-plugin-cyclonedx": "npm:^1.0.0-rc.7" "@cyclonedx/yarn-plugin-cyclonedx": "npm:^1.0.0-rc.7"
"@slack/web-api": "npm:^7.3.4" "@slack/web-api": "npm:^7.3.4"
@ -9359,7 +9297,7 @@ __metadata:
"@types/memoizee": "npm:0.4.11" "@types/memoizee": "npm:0.4.11"
"@types/mime": "npm:4.0.0" "@types/mime": "npm:4.0.0"
"@types/mustache": "npm:^4.2.5" "@types/mustache": "npm:^4.2.5"
"@types/node": "npm:20.16.13" "@types/node": "npm:20.16.14"
"@types/nodemailer": "npm:6.4.16" "@types/nodemailer": "npm:6.4.16"
"@types/owasp-password-strength-test": "npm:1.3.2" "@types/owasp-password-strength-test": "npm:1.3.2"
"@types/pg": "npm:8.11.10" "@types/pg": "npm:8.11.10"