diff --git a/daikoku/javascript/src/components/frontend/api/ApiDocumentation.tsx b/daikoku/javascript/src/components/frontend/api/ApiDocumentation.tsx
index f9efb652c..80b4674fe 100644
--- a/daikoku/javascript/src/components/frontend/api/ApiDocumentation.tsx
+++ b/daikoku/javascript/src/components/frontend/api/ApiDocumentation.tsx
@@ -1,20 +1,17 @@
/* eslint-disable react/display-name */
+import { useQuery, useQueryClient } from '@tanstack/react-query';
import asciidoctor from 'asciidoctor';
+import classNames from 'classnames';
import hljs from 'highlight.js';
import { useContext, useEffect, useState } from 'react';
-import { Link, useMatch, useMatches, useParams } from 'react-router-dom';
-import { useQuery, useQueryClient } from '@tanstack/react-query';
-import classNames from 'classnames';
-import {Option} from '../../utils';
import { I18nContext } from '../../../core';
-import * as Services from '../../../services';
import { converter } from '../../../services/showdown';
-
-import { IApi, IDocPage, IDocumentation, IDocumentationPages, ResponseError, isError } from '../../../types';
+import { IDocPage, IDocumentation, IDocumentationPages, ResponseError, isError } from '../../../types';
import { Spinner } from '../../utils';
import 'highlight.js/styles/monokai.css';
+import { ParamKeyValuePair, useSearchParams } from 'react-router-dom';
const asciidoctorConverter = asciidoctor();
@@ -33,7 +30,7 @@ export const ApiDocumentationCartidge = (props: ApiDocumentationCartidgeProps) =
{pages.map((page) => {
return (
- props.goTo(page.id)}>
+ props.goTo(page.id)}>
{page.title}
{renderLinks(page.children, level + 1)}
@@ -107,7 +104,10 @@ type ApiDocumentationProps = {
export const ApiDocumentation = (props: ApiDocumentationProps) => {
const { Translation } = useContext(I18nContext);
- const [pageId, setPageId] = useState(props.documentation?.pages[0].id)
+ const [searchParams, setSearchParams] = useSearchParams();
+
+ const page = searchParams.get('page');
+ const [pageId, setPageId] = useState(page || props.documentation?.pages[0].id);
const flattenDoc = (pages?: IDocumentationPages): Array => {
if (!pages) {
@@ -117,14 +117,21 @@ export const ApiDocumentation = (props: ApiDocumentationProps) => {
}
}
+ useEffect(() => {
+ if (pageId) {
+ setSearchParams({page: pageId})
+ }
+ }, [pageId])
+
+
const orderedPages = flattenDoc(props.documentation?.pages)
const idx = orderedPages.findIndex(p => p === pageId)
const next = orderedPages[idx + (pageId ? 1 : 2)];
const prev = orderedPages[idx - 1];
- return (<>
-
+ return ();
}
const TypeNotSupportedYet = () => Content type not supported yet !
;
diff --git a/daikoku/javascript/src/components/frontend/api/ApiHome.tsx b/daikoku/javascript/src/components/frontend/api/ApiHome.tsx
index 5b435427c..160bac96b 100644
--- a/daikoku/javascript/src/components/frontend/api/ApiHome.tsx
+++ b/daikoku/javascript/src/components/frontend/api/ApiHome.tsx
@@ -138,7 +138,7 @@ export const ApiHome = ({
const navigate = useNavigate();
const defaultParams = useParams();
- const apiGroupMatch = useMatch('/:teamId/apigroups/:apiGroupId/apis/:apiId/:versionId/:tab');
+ const apiGroupMatch = useMatch('/:teamId/apigroups/:apiGroupId/apis/:apiId/:versionId/:tab*');
const params = Option(apiGroupMatch)
.map((match: any) => match.params)
.getOrElse(defaultParams);
diff --git a/daikoku/javascript/src/components/frontend/api/ApiPricing.tsx b/daikoku/javascript/src/components/frontend/api/ApiPricing.tsx
index 206b3311a..35b33f906 100644
--- a/daikoku/javascript/src/components/frontend/api/ApiPricing.tsx
+++ b/daikoku/javascript/src/components/frontend/api/ApiPricing.tsx
@@ -1,31 +1,31 @@
import { getApolloContext } from '@apollo/client';
-import { constraints, format, type as formType } from '@maif/react-forms';
+import { useQuery } from '@tanstack/react-query';
+import classNames from 'classnames';
import difference from 'lodash/difference';
import find from 'lodash/find';
-import React, { useContext, useEffect } from 'react';
+import React, { useContext, useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
+import { Link, useMatch, useNavigate, useParams, useSearchParams } from 'react-router-dom';
import { ModalContext } from '../../../contexts';
import { I18nContext } from '../../../core';
import * as Services from '../../../services';
import { currencies } from '../../../services/currencies';
-import { IApi, IBaseUsagePlan, isError, isMiniFreeWithQuotas, IState, IStateContext, ISubscription, ISubscriptionDemand, ISubscriptionWithApiInfo, isValidationStepTeamAdmin, ITeamSimple, IUsagePlan, IUsagePlanFreeWithQuotas, IUsagePlanPayPerUse, IUsagePlanQuotasWithLimits, IUsagePlanQuotasWitoutLimit, IValidationStepTeamAdmin } from '../../../types';
-import { INotification } from '../../../types';
+import {
+ IApi, IBaseUsagePlan, isError,
+ isMiniFreeWithQuotas, IState, IStateContext, ISubscription,
+ ISubscriptionDemand, ISubscriptionWithApiInfo, isValidationStepTeamAdmin,
+ ITeamSimple, IUsagePlan
+} from '../../../types';
import {
access,
- api,
- apikey, Can, isPublish, isSubscriptionProcessIsAutomatic, manage,
+ apikey, Can, isPublish, isSubscriptionProcessIsAutomatic,
Option, queryClient, renderPlanInfo, renderPricing, Spinner
} from '../../utils';
-import { ActionWithTeamSelector } from '../../utils/ActionWithTeamSelector';
import { formatPlanType } from '../../utils/formatters';
-import classNames from 'classnames';
-import { Link, useNavigate } from 'react-router-dom';
-import { is } from 'cypress/types/bluebird';
-import { useQuery } from '@tanstack/react-query';
+import { ApiDocumentation } from './ApiDocumentation';
import { ApiRedoc } from './ApiRedoc';
import { ApiSwagger } from './ApiSwagger';
-import { ApiDocumentation } from './ApiDocumentation';
export const currency = (plan?: IBaseUsagePlan) => {
if (!plan) {
@@ -160,32 +160,6 @@ const ApiPricingCard = (props: ApiPricingCardProps) => {
})
}
- const openDocumentationModal = (title: string) => {
- openCustomModal({
- title,
- content: Services.getUsagePlanDocPage(props.api._id, props.plan._id, pageId)} />
- })
- }
-
- const openSwaggerModal = (title: string) => {
- openCustomModal({
- title,
- content:
- })
- }
-
- const openTestModal = (title: string) => {
- openCustomModal({
- title,
- content:
- })
- }
-
return (
@@ -199,9 +173,9 @@ const ApiPricingCard = (props: ApiPricingCardProps) => {
{tenant.display === 'environment' && (
-
-
-
+ swagger
+ test
+ Documentation
)}
@@ -349,6 +323,11 @@ type ApiPricingProps = {
export const ApiPricing = (props: ApiPricingProps) => {
const usagePlansQuery = useQuery(['plans'], () => Services.getVisiblePlans(props.api._id, props.api.currentVersion))
+ const match = useMatch('/:team/:api/:version/pricing/:env/:tab')
+
+ const maybeTab = match?.params.tab
+ const maybeEnv = match?.params.env
+
useEffect(() => {
queryClient.invalidateQueries(['plans'])
}, [props.api])
@@ -364,28 +343,58 @@ export const ApiPricing = (props: ApiPricingProps) => {
props.myTeams.some((team) => plan.authorizedTeams.includes(team._id));
});
- return (
-
- {possibleUsagePlans
- .sort((a, b) => (a.customName || a.type).localeCompare(b.customDescription || b.type))
- .map((plan) =>
- subs.api === props.api._id && subs.plan === plan._id
- )}
- inProgressDemands={props.inProgressDemands.filter(
- (demand) => demand.api === props.api._id && demand.plan === plan._id
- )}
- askForApikeys={props.askForApikeys}
- />
- )}
-
- );
+ if (maybeEnv && maybeTab) {
+ const plan = usagePlansQuery.data.find(p => p.customName === maybeEnv)!
+ return (
+
+
+
+
+
+
{plan.customName}
+
+
+ swagger
+ test
+ Documentation
+
+
+ {maybeTab === 'swagger' &&
}
+ {maybeTab === 'documentation' &&
Services.getUsagePlanDocPage(props.api._id, plan._id, pageId)} />}
+ {maybeTab === 'testing' && }
+
+
+ )
+ } else {
+ return (
+
+ {possibleUsagePlans
+ .sort((a, b) => (a.customName || a.type).localeCompare(b.customDescription || b.type))
+ .map((plan) =>
+ subs.api === props.api._id && subs.plan === plan._id
+ )}
+ inProgressDemands={props.inProgressDemands.filter(
+ (demand) => demand.api === props.api._id && demand.plan === plan._id
+ )}
+ askForApikeys={props.askForApikeys}
+ />
+ )}
+
+ );
+ }
+
} else {
return
}
diff --git a/daikoku/javascript/src/components/frontend/fastMode/FastApiCard.tsx b/daikoku/javascript/src/components/frontend/fastMode/FastApiCard.tsx
index 5ca729ea6..adc68b62c 100644
--- a/daikoku/javascript/src/components/frontend/fastMode/FastApiCard.tsx
+++ b/daikoku/javascript/src/components/frontend/fastMode/FastApiCard.tsx
@@ -45,7 +45,6 @@ export const FastApiCard = (props: FastApiCardProps) => {
: Services.askForApiKey(apiId, team._id, plan._id, motivation)
const adminStep = plan.subscriptionProcess.find(s => isValidationStepTeamAdmin(s))
- console.debug({adminStep, plan})
if (adminStep && isValidationStepTeamAdmin(adminStep)) {
openFormModal<{ motivation: string }>({
title: translate('motivations.modal.title'),
diff --git a/daikoku/javascript/src/components/utils/Option.ts b/daikoku/javascript/src/components/utils/Option.ts
index c6a8303d4..0bcc62cc1 100644
--- a/daikoku/javascript/src/components/utils/Option.ts
+++ b/daikoku/javascript/src/components/utils/Option.ts
@@ -1,18 +1,22 @@
-// export interface TOption
{
-// map(f: (a: A) => B): TOption;
-// flatMap(f: (a: A) => TOption): TOption;
-// fold(ifEmpty: B, f: (a: A) => B): B;
-// orElse(ob: TOption): TOption;
-// getOrElse(a: B): A;
-// getOrNull(): A | undefined
-// isDefined: boolean;
-// exists(f: (a: A) => boolean): boolean;
-// filter(f: (a: A) => boolean): TOption;
-// }
+interface ISome extends IOption {}
+interface INone extends IOption {}
-export const Option = (x) => (x === undefined || x === null ? None : Some(x));
+export interface IOption {
+ map(f: (a: A) => B): ISome | INone;
+ flatMap(f: (a: A) => IOption): IOption | INone;
+ fold(ifEmpty: B, f: (a: A) => B): B;
+ orElse(ob: IOption): IOption | IOption | INone;
+ getOrElse(b: B): A | B;
+ getOrNull(): A | undefined
+ isDefined: boolean;
+ exists(f: (a: A) => boolean): boolean;
+ filter(f: (a: A) => boolean): IOption | INone;
+}
-export const Some = (x) => ({
+
+export const Option = (x: T) => (x === undefined || x === null ? None : Some(x));
+
+export const Some = (x: T) => ({
map: (f) => Option(f(x)),
flatMap: (f) => f(x),
fold: (_ifEmpty, f) => f(x),