diff --git a/samples/musicfestival-backend-dotnet/MusicFestival.Backend.csproj b/samples/musicfestival-backend-dotnet/MusicFestival.Backend.csproj index e17541c..887b07c 100644 --- a/samples/musicfestival-backend-dotnet/MusicFestival.Backend.csproj +++ b/samples/musicfestival-backend-dotnet/MusicFestival.Backend.csproj @@ -8,12 +8,12 @@ - - - - + + + + - + diff --git a/samples/musicfestival-backend-dotnet/Startup.cs b/samples/musicfestival-backend-dotnet/Startup.cs index 99ec729..e332e55 100644 --- a/samples/musicfestival-backend-dotnet/Startup.cs +++ b/samples/musicfestival-backend-dotnet/Startup.cs @@ -39,7 +39,7 @@ public void ConfigureServices(IServiceCollection services) User=sa;Password=Admin123!; Trust Server Certificate=True;Connect Timeout=30"; var connectionstring = _configuration.GetConnectionString("EPiServerDB") - ?? (isMacOs? macOsConnString: localDBConnString); + ?? (isMacOs ? macOsConnString : localDBConnString); services.Configure(o => { o.SetConnectionString(connectionstring); @@ -133,7 +133,10 @@ public void ConfigureServices(IServiceCollection services) o.IncludeNumericContentIdentifier = true; }); - services.AddContentGraph(_configuration, OpenIDConnectOptionsDefaults.AuthenticationScheme); + services.AddContentGraph(OpenIDConnectOptionsDefaults.AuthenticationScheme, options => + { + options.EnablePreviewTokens = true; + }); services.AddHostedService(); } @@ -147,7 +150,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.UseStaticFiles(); app.UseRouting(); app.UseCors(b => b - .WithOrigins(new[] { $"{_frontendUri}"}) + .WithOrigins(new[] { $"{_frontendUri}" }) .WithExposedContentDeliveryApiHeaders() .WithExposedContentDefinitionApiHeaders() .WithHeaders("Authorization") diff --git a/samples/musicfestival-frontend-react/.env b/samples/musicfestival-frontend-react/.env index 0ea85b1..99fcc7c 100644 --- a/samples/musicfestival-frontend-react/.env +++ b/samples/musicfestival-frontend-react/.env @@ -1,4 +1,4 @@ -REACT_APP_CG_PROXY_URL=http://localhost:8082/EpiServer/ContentGraph/CGProxy/Query +REACT_APP_CG_PREVIEW_URL=https://cg.optimizely.com/content/v2 REACT_APP_CONTENT_GRAPH_GATEWAY_URL=https://cg.optimizely.com/content/v2?auth=INPUT_SINGLE_KEY_HERE REACT_APP_LOGIN_AUTHORITY=http://localhost:8082 diff --git a/samples/musicfestival-frontend-react/src/App.tsx b/samples/musicfestival-frontend-react/src/App.tsx index a427f57..67d3673 100644 --- a/samples/musicfestival-frontend-react/src/App.tsx +++ b/samples/musicfestival-frontend-react/src/App.tsx @@ -5,7 +5,7 @@ import ArtistContainerPage from './pages/ArtistContainerPage'; import ArtistDetailsPage from './pages/ArtistDetailsPage'; import authService from './authService'; import { useState } from 'react'; -import { isEditOrPreviewMode } from './helpers/urlHelper' +import { isEditOrPreviewMode, getPreviewTokenFromUrl } from './helpers/urlHelper' import './App.css'; import Footer from './components/Footer'; import { useMutation, useQueryClient } from '@tanstack/react-query'; @@ -16,7 +16,7 @@ import { BlockPage } from './pages/BlockPage'; let previousSavedMessage: any = null; const singleKeyUrl = process.env.REACT_APP_CONTENT_GRAPH_GATEWAY_URL as string -const hmacKeyUrl = process.env.REACT_APP_CG_PROXY_URL as string +const previewUrl = process.env.REACT_APP_CG_PREVIEW_URL as string const App = () => { const queryClient = useQueryClient(); @@ -36,21 +36,18 @@ const App = () => { } }); - authService.getAccessToken().then((_token) => { - _token && setToken(_token) - modeEdit && !_token && !data && authService.login() - }) + const previewToken = getPreviewTokenFromUrl(window.location.search); - variables = generateGQLQueryVars(token, window.location.pathname) + variables = generateGQLQueryVars(previewToken, window.location.pathname) if (modeEdit) { - if (token) { - headers = { 'Authorization': 'Bearer ' + token }; + if (previewToken) { + headers = { 'Authorization': 'Bearer ' + previewToken }; } - url = hmacKeyUrl + url = previewUrl subcribeContentSavedEvent((message: any) => mutate(message)) } - const { data: queryData } = useStartQuery({ endpoint: url, fetchParams: { headers: headers } }, variables, { staleTime: 2000, enabled: !modeEdit || !!token }); + const { data: queryData } = useStartQuery({ endpoint: url, fetchParams: { headers: headers } }, variables, { staleTime: 2000, enabled: !modeEdit || !!previewToken }); data = queryData if (!data) { diff --git a/samples/musicfestival-frontend-react/src/components/SearchButton.tsx b/samples/musicfestival-frontend-react/src/components/SearchButton.tsx index b94b359..a9c3b45 100644 --- a/samples/musicfestival-frontend-react/src/components/SearchButton.tsx +++ b/samples/musicfestival-frontend-react/src/components/SearchButton.tsx @@ -2,7 +2,7 @@ import {useEffect, useRef, useState} from "react"; import {useSearchParams} from "react-router-dom"; import {ArtistAutocompleteQuery, Ranking, useArtistAutocompleteQuery} from "../generated"; import {generateGQLSearchQueryVars} from "../helpers/queryCacheHelper"; -import {getRankingFromSearchParams, isEditOrPreviewMode} from "../helpers/urlHelper"; +import {getRankingFromSearchParams, isEditOrPreviewMode, getPreviewTokenFromUrl } from "../helpers/urlHelper"; type CustomString = string | number | readonly string[] | undefined @@ -18,10 +18,12 @@ function SearchButton({filterValue}: any): JSX.Element { const [orderBy] = useState("ASC") let modeEdit = isEditOrPreviewMode() - let variables = generateGQLSearchQueryVars(token, window.location.pathname, searchValue as string | null, orderBy, ranking); + const previewToken = getPreviewTokenFromUrl(window.location.search); + + let variables = generateGQLSearchQueryVars(previewToken, window.location.pathname, searchValue as string | null, orderBy, ranking); const autocompleteData = useArtistAutocompleteQuery({endpoint: singleKeyUrl}, variables, { staleTime: 2000, - enabled: !modeEdit || !!token + enabled: !modeEdit || !!previewToken }).data; const onSearch = (event: any) => { diff --git a/samples/musicfestival-frontend-react/src/generated.ts b/samples/musicfestival-frontend-react/src/generated.ts index 279e77d..814841f 100644 --- a/samples/musicfestival-frontend-react/src/generated.ts +++ b/samples/musicfestival-frontend-react/src/generated.ts @@ -52,6 +52,7 @@ export type ArtistContainerPage = IContent & { RelativePath?: Maybe; RouteSegment?: Maybe; Saved?: Maybe; + SiteId?: Maybe; StartPublish?: Maybe; Status?: Maybe; StopPublish?: Maybe; @@ -59,10 +60,16 @@ export type ArtistContainerPage = IContent & { _children?: Maybe; _deleted?: Maybe; _fulltext?: Maybe>>; + _link?: Maybe; _modified?: Maybe; _score?: Maybe; }; + +export type ArtistContainerPage_LinkArgs = { + type?: InputMaybe; +}; + export type ArtistContainerPageAutocomplete = { __typename?: 'ArtistContainerPageAutocomplete'; Ancestors?: Maybe>>; @@ -75,6 +82,7 @@ export type ArtistContainerPageAutocomplete = { ParentLink?: Maybe; RelativePath?: Maybe>>; RouteSegment?: Maybe>>; + SiteId?: Maybe>>; Status?: Maybe>>; Url?: Maybe>>; }; @@ -104,6 +112,12 @@ export type ArtistContainerPageAutocompleteRouteSegmentArgs = { }; +export type ArtistContainerPageAutocompleteSiteIdArgs = { + limit?: Scalars['Int']; + value: Scalars['String']; +}; + + export type ArtistContainerPageAutocompleteStatusArgs = { limit?: Scalars['Int']; value: Scalars['String']; @@ -132,6 +146,7 @@ export type ArtistContainerPageFacet = { RelativePath?: Maybe>>; RouteSegment?: Maybe>>; Saved?: Maybe>>; + SiteId?: Maybe>>; StartPublish?: Maybe>>; Status?: Maybe>>; StopPublish?: Maybe>>; @@ -205,6 +220,14 @@ export type ArtistContainerPageFacetSavedArgs = { }; +export type ArtistContainerPageFacetSiteIdArgs = { + filters?: InputMaybe>; + limit?: Scalars['Int']; + orderBy?: InputMaybe; + orderType?: InputMaybe; +}; + + export type ArtistContainerPageFacetStartPublishArgs = { unit?: InputMaybe; value?: InputMaybe; @@ -248,6 +271,7 @@ export type ArtistContainerPageOrderByInput = { RelativePath?: InputMaybe; RouteSegment?: InputMaybe; Saved?: InputMaybe; + SiteId?: InputMaybe; StartPublish?: InputMaybe; Status?: InputMaybe; StopPublish?: InputMaybe; @@ -285,6 +309,7 @@ export type ArtistContainerPageWhereInput = { RelativePath?: InputMaybe; RouteSegment?: InputMaybe; Saved?: InputMaybe; + SiteId?: InputMaybe; StartPublish?: InputMaybe; Status?: InputMaybe; StopPublish?: InputMaybe; @@ -321,6 +346,7 @@ export type ArtistDetailsPage = IContent & { RelativePath?: Maybe; RouteSegment?: Maybe; Saved?: Maybe; + SiteId?: Maybe; StageName?: Maybe; StartPublish?: Maybe; Status?: Maybe; @@ -329,10 +355,16 @@ export type ArtistDetailsPage = IContent & { _children?: Maybe; _deleted?: Maybe; _fulltext?: Maybe>>; + _link?: Maybe; _modified?: Maybe; _score?: Maybe; }; + +export type ArtistDetailsPage_LinkArgs = { + type?: InputMaybe; +}; + export type ArtistDetailsPageAutocomplete = { __typename?: 'ArtistDetailsPageAutocomplete'; Ancestors?: Maybe>>; @@ -349,6 +381,7 @@ export type ArtistDetailsPageAutocomplete = { ParentLink?: Maybe; RelativePath?: Maybe>>; RouteSegment?: Maybe>>; + SiteId?: Maybe>>; StageName?: Maybe>>; Status?: Maybe>>; Url?: Maybe>>; @@ -403,6 +436,12 @@ export type ArtistDetailsPageAutocompleteRouteSegmentArgs = { }; +export type ArtistDetailsPageAutocompleteSiteIdArgs = { + limit?: Scalars['Int']; + value: Scalars['String']; +}; + + export type ArtistDetailsPageAutocompleteStageNameArgs = { limit?: Scalars['Int']; value: Scalars['String']; @@ -444,6 +483,7 @@ export type ArtistDetailsPageFacet = { RelativePath?: Maybe>>; RouteSegment?: Maybe>>; Saved?: Maybe>>; + SiteId?: Maybe>>; StageName?: Maybe>>; StartPublish?: Maybe>>; Status?: Maybe>>; @@ -570,6 +610,14 @@ export type ArtistDetailsPageFacetSavedArgs = { }; +export type ArtistDetailsPageFacetSiteIdArgs = { + filters?: InputMaybe>; + limit?: Scalars['Int']; + orderBy?: InputMaybe; + orderType?: InputMaybe; +}; + + export type ArtistDetailsPageFacetStageNameArgs = { filters?: InputMaybe>; limit?: Scalars['Int']; @@ -628,6 +676,7 @@ export type ArtistDetailsPageOrderByInput = { RelativePath?: InputMaybe; RouteSegment?: InputMaybe; Saved?: InputMaybe; + SiteId?: InputMaybe; StageName?: InputMaybe; StartPublish?: InputMaybe; Status?: InputMaybe; @@ -673,6 +722,7 @@ export type ArtistDetailsPageWhereInput = { RelativePath?: InputMaybe; RouteSegment?: InputMaybe; Saved?: InputMaybe; + SiteId?: InputMaybe; StageName?: InputMaybe; StartPublish?: InputMaybe; Status?: InputMaybe; @@ -771,6 +821,7 @@ export type BuyTicketBlock = IContent & { RelativePath?: Maybe; RouteSegment?: Maybe; Saved?: Maybe; + SiteId?: Maybe; StartPublish?: Maybe; Status?: Maybe; StopPublish?: Maybe; @@ -778,10 +829,16 @@ export type BuyTicketBlock = IContent & { _children?: Maybe; _deleted?: Maybe; _fulltext?: Maybe>>; + _link?: Maybe; _modified?: Maybe; _score?: Maybe; }; + +export type BuyTicketBlock_LinkArgs = { + type?: InputMaybe; +}; + export type BuyTicketBlockAutocomplete = { __typename?: 'BuyTicketBlockAutocomplete'; Ancestors?: Maybe>>; @@ -796,6 +853,7 @@ export type BuyTicketBlockAutocomplete = { ParentLink?: Maybe; RelativePath?: Maybe>>; RouteSegment?: Maybe>>; + SiteId?: Maybe>>; Status?: Maybe>>; Url?: Maybe>>; }; @@ -837,6 +895,12 @@ export type BuyTicketBlockAutocompleteRouteSegmentArgs = { }; +export type BuyTicketBlockAutocompleteSiteIdArgs = { + limit?: Scalars['Int']; + value: Scalars['String']; +}; + + export type BuyTicketBlockAutocompleteStatusArgs = { limit?: Scalars['Int']; value: Scalars['String']; @@ -867,6 +931,7 @@ export type BuyTicketBlockFacet = { RelativePath?: Maybe>>; RouteSegment?: Maybe>>; Saved?: Maybe>>; + SiteId?: Maybe>>; StartPublish?: Maybe>>; Status?: Maybe>>; StopPublish?: Maybe>>; @@ -956,6 +1021,14 @@ export type BuyTicketBlockFacetSavedArgs = { }; +export type BuyTicketBlockFacetSiteIdArgs = { + filters?: InputMaybe>; + limit?: Scalars['Int']; + orderBy?: InputMaybe; + orderType?: InputMaybe; +}; + + export type BuyTicketBlockFacetStartPublishArgs = { unit?: InputMaybe; value?: InputMaybe; @@ -1001,6 +1074,7 @@ export type BuyTicketBlockOrderByInput = { RelativePath?: InputMaybe; RouteSegment?: InputMaybe; Saved?: InputMaybe; + SiteId?: InputMaybe; StartPublish?: InputMaybe; Status?: InputMaybe; StopPublish?: InputMaybe; @@ -1040,6 +1114,7 @@ export type BuyTicketBlockWhereInput = { RelativePath?: InputMaybe; RouteSegment?: InputMaybe; Saved?: InputMaybe; + SiteId?: InputMaybe; StartPublish?: InputMaybe; Status?: InputMaybe; StopPublish?: InputMaybe; @@ -1132,6 +1207,7 @@ export type Content = IContent & { RelativePath?: Maybe; RouteSegment?: Maybe; Saved?: Maybe; + SiteId?: Maybe; StartPublish?: Maybe; Status?: Maybe; StopPublish?: Maybe; @@ -1139,14 +1215,21 @@ export type Content = IContent & { _children?: Maybe; _deleted?: Maybe; _fulltext?: Maybe>>; + _link?: Maybe; _modified?: Maybe; _score?: Maybe; }; + +export type Content_LinkArgs = { + type?: InputMaybe; +}; + export type ContentAreaItemModel = { __typename?: 'ContentAreaItemModel'; ContentLink?: Maybe; DisplayOption?: Maybe; + InlineBlock?: Maybe; Tag?: Maybe; }; @@ -1154,6 +1237,7 @@ export type ContentAreaItemModelAutocomplete = { __typename?: 'ContentAreaItemModelAutocomplete'; ContentLink?: Maybe; DisplayOption?: Maybe>>; + InlineBlock?: Maybe; Tag?: Maybe>>; }; @@ -1173,6 +1257,7 @@ export type ContentAreaItemModelFacet = { __typename?: 'ContentAreaItemModelFacet'; ContentLink?: Maybe; DisplayOption?: Maybe>>; + InlineBlock?: Maybe; Tag?: Maybe>>; }; @@ -1195,12 +1280,14 @@ export type ContentAreaItemModelFacetTagArgs = { export type ContentAreaItemModelOrderByInput = { ContentLink?: InputMaybe; DisplayOption?: InputMaybe; + InlineBlock?: InputMaybe; Tag?: InputMaybe; }; export type ContentAreaItemModelWhereInput = { ContentLink?: InputMaybe; DisplayOption?: InputMaybe; + InlineBlock?: InputMaybe; Tag?: InputMaybe; }; @@ -1215,6 +1302,7 @@ export type ContentAutocomplete = { ParentLink?: Maybe; RelativePath?: Maybe>>; RouteSegment?: Maybe>>; + SiteId?: Maybe>>; Status?: Maybe>>; Url?: Maybe>>; }; @@ -1244,6 +1332,12 @@ export type ContentAutocompleteRouteSegmentArgs = { }; +export type ContentAutocompleteSiteIdArgs = { + limit?: Scalars['Int']; + value: Scalars['String']; +}; + + export type ContentAutocompleteStatusArgs = { limit?: Scalars['Int']; value: Scalars['String']; @@ -1275,6 +1369,7 @@ export type ContentBlock = IContent & { RelativePath?: Maybe; RouteSegment?: Maybe; Saved?: Maybe; + SiteId?: Maybe; StartPublish?: Maybe; Status?: Maybe; StopPublish?: Maybe; @@ -1283,10 +1378,16 @@ export type ContentBlock = IContent & { _children?: Maybe; _deleted?: Maybe; _fulltext?: Maybe>>; + _link?: Maybe; _modified?: Maybe; _score?: Maybe; }; + +export type ContentBlock_LinkArgs = { + type?: InputMaybe; +}; + export type ContentBlockAutocomplete = { __typename?: 'ContentBlockAutocomplete'; Ancestors?: Maybe>>; @@ -1302,6 +1403,7 @@ export type ContentBlockAutocomplete = { ParentLink?: Maybe; RelativePath?: Maybe>>; RouteSegment?: Maybe>>; + SiteId?: Maybe>>; Status?: Maybe>>; Title?: Maybe>>; Url?: Maybe>>; @@ -1350,6 +1452,12 @@ export type ContentBlockAutocompleteRouteSegmentArgs = { }; +export type ContentBlockAutocompleteSiteIdArgs = { + limit?: Scalars['Int']; + value: Scalars['String']; +}; + + export type ContentBlockAutocompleteStatusArgs = { limit?: Scalars['Int']; value: Scalars['String']; @@ -1387,6 +1495,7 @@ export type ContentBlockFacet = { RelativePath?: Maybe>>; RouteSegment?: Maybe>>; Saved?: Maybe>>; + SiteId?: Maybe>>; StartPublish?: Maybe>>; Status?: Maybe>>; StopPublish?: Maybe>>; @@ -1485,6 +1594,14 @@ export type ContentBlockFacetSavedArgs = { }; +export type ContentBlockFacetSiteIdArgs = { + filters?: InputMaybe>; + limit?: Scalars['Int']; + orderBy?: InputMaybe; + orderType?: InputMaybe; +}; + + export type ContentBlockFacetStartPublishArgs = { unit?: InputMaybe; value?: InputMaybe; @@ -1539,6 +1656,7 @@ export type ContentBlockOrderByInput = { RelativePath?: InputMaybe; RouteSegment?: InputMaybe; Saved?: InputMaybe; + SiteId?: InputMaybe; StartPublish?: InputMaybe; Status?: InputMaybe; StopPublish?: InputMaybe; @@ -1580,6 +1698,7 @@ export type ContentBlockWhereInput = { RelativePath?: InputMaybe; RouteSegment?: InputMaybe; Saved?: InputMaybe; + SiteId?: InputMaybe; StartPublish?: InputMaybe; Status?: InputMaybe; StopPublish?: InputMaybe; @@ -1608,6 +1727,7 @@ export type ContentFacet = { RelativePath?: Maybe>>; RouteSegment?: Maybe>>; Saved?: Maybe>>; + SiteId?: Maybe>>; StartPublish?: Maybe>>; Status?: Maybe>>; StopPublish?: Maybe>>; @@ -1681,6 +1801,14 @@ export type ContentFacetSavedArgs = { }; +export type ContentFacetSiteIdArgs = { + filters?: InputMaybe>; + limit?: Scalars['Int']; + orderBy?: InputMaybe; + orderType?: InputMaybe; +}; + + export type ContentFacetStartPublishArgs = { unit?: InputMaybe; value?: InputMaybe; @@ -1897,6 +2025,7 @@ export type ContentOrderByInput = { RelativePath?: InputMaybe; RouteSegment?: InputMaybe; Saved?: InputMaybe; + SiteId?: InputMaybe; StartPublish?: InputMaybe; Status?: InputMaybe; StopPublish?: InputMaybe; @@ -1981,6 +2110,7 @@ export type ContentWhereInput = { RelativePath?: InputMaybe; RouteSegment?: InputMaybe; Saved?: InputMaybe; + SiteId?: InputMaybe; StartPublish?: InputMaybe; Status?: InputMaybe; StopPublish?: InputMaybe; @@ -2100,6 +2230,7 @@ export type IContent = { RelativePath?: Maybe; RouteSegment?: Maybe; Saved?: Maybe; + SiteId?: Maybe; StartPublish?: Maybe; Status?: Maybe; StopPublish?: Maybe; @@ -2107,10 +2238,16 @@ export type IContent = { _children?: Maybe; _deleted?: Maybe; _fulltext?: Maybe>>; + _link?: Maybe; _modified?: Maybe; _score?: Maybe; }; + +export type IContent_LinkArgs = { + type?: InputMaybe; +}; + export type ImageFile = IContent & { __typename?: 'ImageFile'; Ancestors?: Maybe>>; @@ -2130,6 +2267,7 @@ export type ImageFile = IContent & { RelativePath?: Maybe; RouteSegment?: Maybe; Saved?: Maybe; + SiteId?: Maybe; StartPublish?: Maybe; Status?: Maybe; StopPublish?: Maybe; @@ -2138,10 +2276,16 @@ export type ImageFile = IContent & { _children?: Maybe; _deleted?: Maybe; _fulltext?: Maybe>>; + _link?: Maybe; _modified?: Maybe; _score?: Maybe; }; + +export type ImageFile_LinkArgs = { + type?: InputMaybe; +}; + export type ImageFileAutocomplete = { __typename?: 'ImageFileAutocomplete'; Ancestors?: Maybe>>; @@ -2155,6 +2299,7 @@ export type ImageFileAutocomplete = { ParentLink?: Maybe; RelativePath?: Maybe>>; RouteSegment?: Maybe>>; + SiteId?: Maybe>>; Status?: Maybe>>; Thumbnail?: Maybe; Url?: Maybe>>; @@ -2191,6 +2336,12 @@ export type ImageFileAutocompleteRouteSegmentArgs = { }; +export type ImageFileAutocompleteSiteIdArgs = { + limit?: Scalars['Int']; + value: Scalars['String']; +}; + + export type ImageFileAutocompleteStatusArgs = { limit?: Scalars['Int']; value: Scalars['String']; @@ -2221,6 +2372,7 @@ export type ImageFileFacet = { RelativePath?: Maybe>>; RouteSegment?: Maybe>>; Saved?: Maybe>>; + SiteId?: Maybe>>; StartPublish?: Maybe>>; Status?: Maybe>>; StopPublish?: Maybe>>; @@ -2311,6 +2463,14 @@ export type ImageFileFacetSavedArgs = { }; +export type ImageFileFacetSiteIdArgs = { + filters?: InputMaybe>; + limit?: Scalars['Int']; + orderBy?: InputMaybe; + orderType?: InputMaybe; +}; + + export type ImageFileFacetStartPublishArgs = { unit?: InputMaybe; value?: InputMaybe; @@ -2356,6 +2516,7 @@ export type ImageFileOrderByInput = { RelativePath?: InputMaybe; RouteSegment?: InputMaybe; Saved?: InputMaybe; + SiteId?: InputMaybe; StartPublish?: InputMaybe; Status?: InputMaybe; StopPublish?: InputMaybe; @@ -2396,6 +2557,7 @@ export type ImageFileWhereInput = { RelativePath?: InputMaybe; RouteSegment?: InputMaybe; Saved?: InputMaybe; + SiteId?: InputMaybe; StartPublish?: InputMaybe; Status?: InputMaybe; StopPublish?: InputMaybe; @@ -2428,6 +2590,7 @@ export type ImagePage = IContent & { RelativePath?: Maybe; RouteSegment?: Maybe; Saved?: Maybe; + SiteId?: Maybe; StartPublish?: Maybe; Status?: Maybe; StopPublish?: Maybe; @@ -2436,10 +2599,16 @@ export type ImagePage = IContent & { _children?: Maybe; _deleted?: Maybe; _fulltext?: Maybe>>; + _link?: Maybe; _modified?: Maybe; _score?: Maybe; }; + +export type ImagePage_LinkArgs = { + type?: InputMaybe; +}; + export type ImagePageAutocomplete = { __typename?: 'ImagePageAutocomplete'; Ancestors?: Maybe>>; @@ -2453,6 +2622,7 @@ export type ImagePageAutocomplete = { ParentLink?: Maybe; RelativePath?: Maybe>>; RouteSegment?: Maybe>>; + SiteId?: Maybe>>; Status?: Maybe>>; Thumbnail?: Maybe; Url?: Maybe>>; @@ -2489,6 +2659,12 @@ export type ImagePageAutocompleteRouteSegmentArgs = { }; +export type ImagePageAutocompleteSiteIdArgs = { + limit?: Scalars['Int']; + value: Scalars['String']; +}; + + export type ImagePageAutocompleteStatusArgs = { limit?: Scalars['Int']; value: Scalars['String']; @@ -2520,6 +2696,7 @@ export type ImagePageFacet = { RelativePath?: Maybe>>; RouteSegment?: Maybe>>; Saved?: Maybe>>; + SiteId?: Maybe>>; StartPublish?: Maybe>>; Status?: Maybe>>; StopPublish?: Maybe>>; @@ -2618,6 +2795,14 @@ export type ImagePageFacetSavedArgs = { }; +export type ImagePageFacetSiteIdArgs = { + filters?: InputMaybe>; + limit?: Scalars['Int']; + orderBy?: InputMaybe; + orderType?: InputMaybe; +}; + + export type ImagePageFacetStartPublishArgs = { unit?: InputMaybe; value?: InputMaybe; @@ -2664,6 +2849,7 @@ export type ImagePageOrderByInput = { RelativePath?: InputMaybe; RouteSegment?: InputMaybe; Saved?: InputMaybe; + SiteId?: InputMaybe; StartPublish?: InputMaybe; Status?: InputMaybe; StopPublish?: InputMaybe; @@ -2705,6 +2891,7 @@ export type ImagePageWhereInput = { RelativePath?: InputMaybe; RouteSegment?: InputMaybe; Saved?: InputMaybe; + SiteId?: InputMaybe; StartPublish?: InputMaybe; Status?: InputMaybe; StopPublish?: InputMaybe; @@ -2717,6 +2904,43 @@ export type ImagePageWhereInput = { _or?: InputMaybe>>; }; +export type InlineBlockPropertyModel = { + __typename?: 'InlineBlockPropertyModel'; + ContentType?: Maybe>>; +}; + +export type InlineBlockPropertyModelAutocomplete = { + __typename?: 'InlineBlockPropertyModelAutocomplete'; + ContentType?: Maybe>>; +}; + + +export type InlineBlockPropertyModelAutocompleteContentTypeArgs = { + limit?: Scalars['Int']; + value: Scalars['String']; +}; + +export type InlineBlockPropertyModelFacet = { + __typename?: 'InlineBlockPropertyModelFacet'; + ContentType?: Maybe>>; +}; + + +export type InlineBlockPropertyModelFacetContentTypeArgs = { + filters?: InputMaybe>; + limit?: Scalars['Int']; + orderBy?: InputMaybe; + orderType?: InputMaybe; +}; + +export type InlineBlockPropertyModelOrderByInput = { + ContentType?: InputMaybe; +}; + +export type InlineBlockPropertyModelWhereInput = { + ContentType?: InputMaybe; +}; + export type IntFilterInput = { /** `boost` influences the weight of a field by boosting a match with a number (default: 1) — counts more towards the eventual relevance score which can be projected with `_score` — at query time. Note that `boost` cannot be a negative number. */ boost?: InputMaybe; @@ -2762,6 +2986,7 @@ export type LandingPage = IContent & { RelativePath?: Maybe; RouteSegment?: Maybe; Saved?: Maybe; + SiteId?: Maybe; StartPublish?: Maybe; Status?: Maybe; StopPublish?: Maybe; @@ -2771,10 +2996,16 @@ export type LandingPage = IContent & { _children?: Maybe; _deleted?: Maybe; _fulltext?: Maybe>>; + _link?: Maybe; _modified?: Maybe; _score?: Maybe; }; + +export type LandingPage_LinkArgs = { + type?: InputMaybe; +}; + export type LandingPageAutocomplete = { __typename?: 'LandingPageAutocomplete'; Ancestors?: Maybe>>; @@ -2792,6 +3023,7 @@ export type LandingPageAutocomplete = { ParentLink?: Maybe; RelativePath?: Maybe>>; RouteSegment?: Maybe>>; + SiteId?: Maybe>>; Status?: Maybe>>; Subtitle?: Maybe>>; Title?: Maybe>>; @@ -2829,6 +3061,12 @@ export type LandingPageAutocompleteRouteSegmentArgs = { }; +export type LandingPageAutocompleteSiteIdArgs = { + limit?: Scalars['Int']; + value: Scalars['String']; +}; + + export type LandingPageAutocompleteStatusArgs = { limit?: Scalars['Int']; value: Scalars['String']; @@ -2930,6 +3168,7 @@ export type LandingPageFacet = { RelativePath?: Maybe>>; RouteSegment?: Maybe>>; Saved?: Maybe>>; + SiteId?: Maybe>>; StartPublish?: Maybe>>; Status?: Maybe>>; StopPublish?: Maybe>>; @@ -3013,6 +3252,14 @@ export type LandingPageFacetSavedArgs = { }; +export type LandingPageFacetSiteIdArgs = { + filters?: InputMaybe>; + limit?: Scalars['Int']; + orderBy?: InputMaybe; + orderType?: InputMaybe; +}; + + export type LandingPageFacetStartPublishArgs = { unit?: InputMaybe; value?: InputMaybe; @@ -3077,6 +3324,7 @@ export type LandingPageOrderByInput = { RelativePath?: InputMaybe; RouteSegment?: InputMaybe; Saved?: InputMaybe; + SiteId?: InputMaybe; StartPublish?: InputMaybe; Status?: InputMaybe; StopPublish?: InputMaybe; @@ -3121,6 +3369,7 @@ export type LandingPageWhereInput = { RelativePath?: InputMaybe; RouteSegment?: InputMaybe; Saved?: InputMaybe; + SiteId?: InputMaybe; StartPublish?: InputMaybe; Status?: InputMaybe; StopPublish?: InputMaybe; @@ -3134,6 +3383,10 @@ export type LandingPageWhereInput = { _or?: InputMaybe>>; }; +export enum LinkTypes { + Default = 'DEFAULT' +} + export enum Locales { All = 'ALL', Neutral = 'NEUTRAL', @@ -3390,7 +3643,7 @@ export enum Ranking { BoostOnly = 'BOOST_ONLY', Doc = 'DOC', Relevance = 'RELEVANCE', - Semantic = "SEMANTIC", + Semantic = 'SEMANTIC' } export type SearchableStringFilterInput = { @@ -3402,10 +3655,14 @@ export type SearchableStringFilterInput = { eq?: InputMaybe; /** `exist` matches results that have this field. */ exist?: InputMaybe; + /** enables supporting fuzzy matching on the query terms (keywords), which returns items that contain terms in the content similar to the keywords, as measured by a _Levenshtein edit distance_. An edit distance is the number of one-character changes needed to turn one term into another. The edit distance is based on the length of the term. */ + fuzzy?: InputMaybe; /** `in` matches with 1 or more exact values in a list. Example: `in: ["word1", "word2", "this is a phrase"]` */ in?: InputMaybe>>; /** `like` matches on substrings with wildcard support: `%` to match on 0 or more characters, `_` to match on any character. */ like?: InputMaybe; + /** `match` performs full-text search on a word or phrase where less relevant items are also returned. The `match` operator is only supported for `searchable` fields. It will improve fulltext search by making it easier to match on words. More exact matches will be ranked higher, less exact matches will be ranked lower. The `match` operator is supported with synonyms and fuzzy search. */ + match?: InputMaybe; /** `not_eq` retrieves results not matching with an exact (but case-insensitive) value. */ notEq?: InputMaybe; /** `not_in` returns results that do not match with 1 or more exact values in a list. Example: `not_in: ["word1", "word2", "this is a phrase"]` */ @@ -3430,10 +3687,16 @@ export type SiteDefinition = { _children?: Maybe; _deleted?: Maybe; _fulltext?: Maybe>>; + _link?: Maybe; _modified?: Maybe; _score?: Maybe; }; + +export type SiteDefinition_LinkArgs = { + type?: InputMaybe; +}; + export type SiteDefinitionAutocomplete = { __typename?: 'SiteDefinitionAutocomplete'; ContentLink?: Maybe; @@ -3688,6 +3951,8 @@ export type StringFilterInput = { eq?: InputMaybe; /** `exist` matches results that have this field. */ exist?: InputMaybe; + /** enables supporting fuzzy matching on the query terms (keywords), which returns items that contain terms in the content similar to the keywords, as measured by a _Levenshtein edit distance_. An edit distance is the number of one-character changes needed to turn one term into another. The edit distance is based on the length of the term. */ + fuzzy?: InputMaybe; /** `in` matches with 1 or more exact values in a list. Example: `in: ["word1", "word2", "this is a phrase"]` */ in?: InputMaybe>>; /** `like` matches on substrings with wildcard support: `%` to match on 0 or more characters, `_` to match on any character. */ @@ -3884,10 +4149,10 @@ export const useArtistAutocompleteQuery = < options ); export const ArtistSearchDocument = ` - query ArtistSearch($searchParam: String!, $locales: Locales!, $order: OrderBy, $ranking: Ranking) { + query ArtistSearch($searchParam: String!, $locales: Locales!, $order: OrderBy) { ArtistDetailsPage( locale: [$locales] - orderBy: {_ranking: $ranking, ArtistName: $order} + orderBy: {_ranking: RELEVANCE, ArtistName: $order} where: {_or: [{Name: {contains: $searchParam, boost: 10}}, {Name: {startsWith: $searchParam, boost: 10}}, {StageName: {startsWith: $searchParam}}]} ) { items { @@ -3932,10 +4197,10 @@ export const useArtistSearchQuery = < options ); export const OtherContentSearchDocument = ` - query OtherContentSearch($searchParam: String!, $locales: Locales!, $order: OrderBy, $ranking: Ranking) { + query OtherContentSearch($searchParam: String!, $locales: Locales!, $order: OrderBy) { Content( locale: [$locales] - orderBy: {_ranking: $ranking, Name: $order} + orderBy: {_ranking: RELEVANCE, Name: $order} where: {_or: [{Name: {contains: $searchParam, boost: 10}}, {Name: {startsWith: $searchParam, boost: 10}}], _and: {ContentType: {notEq: "ArtistDetailsPage"}}} ) { items { diff --git a/samples/musicfestival-frontend-react/src/helpers/queryCacheHelper.ts b/samples/musicfestival-frontend-react/src/helpers/queryCacheHelper.ts index 2914ef2..8249cf7 100644 --- a/samples/musicfestival-frontend-react/src/helpers/queryCacheHelper.ts +++ b/samples/musicfestival-frontend-react/src/helpers/queryCacheHelper.ts @@ -4,7 +4,7 @@ import { ContentSavedMessage } from "../models/ContentSavedMessage"; import { extractParams, isEditOrPreviewMode } from "./urlHelper"; const generateGQLQueryVars = (token: string, pathname: string): any => { - const { relativePath, locales, language, contentId, workId } = extractParams(pathname) + const { relativePath, locales, language, contentId, workId } = extractParams(token, pathname) let variables: any = { relativePath, locales: locales as Locales, language, statusEqual: "Published" }; if (isEditOrPreviewMode() && token) { variables = workId === undefined @@ -16,7 +16,7 @@ const generateGQLQueryVars = (token: string, pathname: string): any => { } const generateGQLSearchQueryVars = (token: string, pathname: string, searchParam: string | null, sortOption: string, ranking: Ranking = Ranking.Relevance): any => { - const { locales } = extractParams(pathname) + const { locales } = extractParams(token, pathname) let variables: any = { locales: locales as Locales, searchParam: searchParam, order: sortOption, ranking: ranking }; if (isEditOrPreviewMode() && token) { variables = { locales: locales as Locales, searchParam, sortOption, ranking }; diff --git a/samples/musicfestival-frontend-react/src/helpers/urlHelper.ts b/samples/musicfestival-frontend-react/src/helpers/urlHelper.ts index e97d6e5..5b3e81e 100644 --- a/samples/musicfestival-frontend-react/src/helpers/urlHelper.ts +++ b/samples/musicfestival-frontend-react/src/helpers/urlHelper.ts @@ -1,4 +1,7 @@ import {Ranking} from "../generated"; +import { Buffer } from "buffer"; +import { Payload } from "../models/Payload"; + const isEditOrPreviewMode = () => { const params = window.location.search.split(/[&?]+/); @@ -14,10 +17,15 @@ const getImageUrl = (path = "") => { return path.startsWith("http") ? path : siteUrl + path } -const extractParams = (urlPath: string) => { +const extractParams = (token: string, urlPath: string) => { + var payload: Payload = {}; + + if (token) { + const base64String = token.split('.')[1] + payload = JSON.parse(Buffer.from(base64String, 'base64').toString()); + } + let relativePath = (urlPath.length > 1 && urlPath != "/search") ? urlPath : '/en' - let contentId - let workId = undefined const epiContentPrefix = "/EPiServer/CMS/Content/"; if (relativePath.startsWith(epiContentPrefix)) { @@ -29,13 +37,6 @@ const extractParams = (urlPath: string) => { } if (relativePath.includes(",")) { - const [, , idString] = relativePath.split(",") - if (idString.includes("_")) { - [contentId, workId] = idString.split("_").map(x => parseInt(x)); - - } else { - contentId = parseInt(idString) - } relativePath = relativePath.substring(0, relativePath.indexOf(',')); } @@ -46,7 +47,10 @@ const extractParams = (urlPath: string) => { const urlSegments = relativePath.split('/') const language = urlSegments.length ? urlSegments.find(s => s.length === 2) : "en" - return {relativePath, locales: language, language, contentId, workId} + const contentId = payload.c_id && parseInt(payload.c_id!.toString()); + const workId = payload.c_ver && parseInt(payload.c_ver!.toString()); + + return { relativePath, locales: language, language, contentId: contentId, workId: workId } } const getRankingFromSearchParams = (searchParams: URLSearchParams): Ranking => { @@ -59,4 +63,12 @@ const getRankingFromSearchParams = (searchParams: URLSearchParams): Ranking => { return Ranking.Relevance; } -export {isEditOrPreviewMode, extractParams, getImageUrl, getRankingFromSearchParams} \ No newline at end of file +const getPreviewTokenFromUrl = (queryString: string) => { + const urlParams = new URLSearchParams(queryString); + const previewToken = urlParams.get('preview_token') ?? ""; + + return previewToken; +} + + +export {isEditOrPreviewMode, extractParams, getImageUrl, getRankingFromSearchParams, getPreviewTokenFromUrl} \ No newline at end of file diff --git a/samples/musicfestival-frontend-react/src/models/Payload.ts b/samples/musicfestival-frontend-react/src/models/Payload.ts new file mode 100644 index 0000000..c7f2650 --- /dev/null +++ b/samples/musicfestival-frontend-react/src/models/Payload.ts @@ -0,0 +1,4 @@ +export interface Payload { + c_id?: number; + c_ver?: number; +} \ No newline at end of file diff --git a/samples/musicfestival-frontend-react/src/pages/SearchPage.tsx b/samples/musicfestival-frontend-react/src/pages/SearchPage.tsx index 04644f6..bc985a8 100644 --- a/samples/musicfestival-frontend-react/src/pages/SearchPage.tsx +++ b/samples/musicfestival-frontend-react/src/pages/SearchPage.tsx @@ -21,7 +21,7 @@ import { subcribeContentSavedEvent } from "../helpers/contentSavedEvent"; let previousSavedMessage: any = null; const singleKeyUrl = process.env.REACT_APP_CONTENT_GRAPH_GATEWAY_URL as string -const hmacKeyUrl = process.env.REACT_APP_CG_PROXY_URL as string +const previewUrl = process.env.REACT_APP_CG_PREVIEW_URL as string function SearchPage() { console.log("Start") @@ -80,7 +80,7 @@ function SearchPage() { if (token) { headers = { 'Authorization': 'Bearer ' + token } } - url = hmacKeyUrl + url = previewUrl subcribeContentSavedEvent((message: any) => mutate(message)) }