Error processing and search fixes in Admin UI (#2666)
* Error processing and search fixes in Admin UI * Fixed permalink validation in the page admin modal
This commit is contained in:
Родитель
a8b70bff88
Коммит
dfe3d6c382
|
@ -6,7 +6,7 @@
|
|||
"packages": {
|
||||
"": {
|
||||
"name": "apim-developer-portal",
|
||||
"version": "2.29.0",
|
||||
"version": "2.30.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@azure/api-management-custom-widgets-scaffolder": "^1.0.0-beta.4",
|
||||
|
|
|
@ -6,11 +6,10 @@ import { EventManager } from '@paperbits/common/events';
|
|||
import { ViewManager } from '@paperbits/common/ui';
|
||||
import { IMediaService } from '@paperbits/common/media';
|
||||
import { MediaContract } from '@paperbits/common/media/mediaContract';
|
||||
import { Query, Operator } from '@paperbits/common/persistence';
|
||||
import { MimeTypes } from '@paperbits/common';
|
||||
import { Checkbox, DefaultButton, IconButton, IIconProps, Image, ImageFit, IOverflowSetItemProps, Link, Modal, OverflowSet, SearchBox, Spinner, Stack, Text, TextField } from '@fluentui/react';
|
||||
import { DeleteConfirmationOverlay } from '../utils/components/deleteConfirmationOverlay';
|
||||
import { getAllValues, getThumbnailUrl } from '../utils/helpers';
|
||||
import { createSearchQuery, getAllValues, getThumbnailUrl } from '../utils/helpers';
|
||||
import { ImageDetailsModal } from './imageDetailsModal';
|
||||
import { NonImageDetailsModal } from './nonImageDetailsModal';
|
||||
|
||||
|
@ -69,11 +68,7 @@ export class MediaModal extends React.Component<MediaModalProps, MediaModalState
|
|||
|
||||
searchMedia = async (searchPattern: string = ''): Promise<void> => {
|
||||
this.setState({ isLoading: true });
|
||||
const query = Query.from().orderBy('fileName');
|
||||
if (searchPattern) {
|
||||
query.where('fileName', Operator.contains, searchPattern);
|
||||
}
|
||||
|
||||
const query = createSearchQuery(searchPattern, 'fileName');
|
||||
const mediaSearchResult = await this.mediaService.search(query);
|
||||
const allMedia = await getAllValues(mediaSearchResult, mediaSearchResult.value);
|
||||
this.setState({ media: allMedia, isLoading: false });
|
||||
|
|
|
@ -6,9 +6,8 @@ import { EventManager } from '@paperbits/common/events';
|
|||
import { ViewManager } from '@paperbits/common/ui';
|
||||
import { IMediaService } from '@paperbits/common/media';
|
||||
import { MediaContract } from '@paperbits/common/media/mediaContract';
|
||||
import { Query, Operator } from '@paperbits/common/persistence';
|
||||
import { DefaultButton, IIconProps, Image, ImageFit, IOverflowSetItemProps, Link, Modal, SearchBox, Stack, Text } from '@fluentui/react';
|
||||
import { getAllValues } from '../utils/helpers';
|
||||
import { createSearchQuery, getAllValues } from '../utils/helpers';
|
||||
import { NonImageDetailsModal } from './nonImageDetailsModal';
|
||||
|
||||
interface MediaSelectionItemModalState {
|
||||
|
@ -50,11 +49,7 @@ export class MediaSelectionItemModal extends React.Component<MediaSelectionItemM
|
|||
}
|
||||
|
||||
searchMedia = async (searchPattern: string = ''): Promise<void> => {
|
||||
const query = Query.from().orderBy('fileName');
|
||||
if (searchPattern) {
|
||||
query.where('fileName', Operator.contains, searchPattern);
|
||||
}
|
||||
|
||||
const query = createSearchQuery(searchPattern, 'fileName');
|
||||
const mediaSearchResult = await this.mediaService.search(query);
|
||||
const allMedia = await getAllValues(mediaSearchResult, mediaSearchResult.value);
|
||||
this.setState({ media: allMedia });
|
||||
|
@ -171,8 +166,10 @@ export class MediaSelectionItemModal extends React.Component<MediaSelectionItemM
|
|||
</Stack.Item>
|
||||
</Stack>
|
||||
<Stack horizontal tokens={{ childrenGap: 20 }} wrap>
|
||||
{this.state.media.map(mediaItem =>
|
||||
this.renderMediaItem(mediaItem)
|
||||
{this.state.media.length === 0
|
||||
? <Text block>It seems that you don't have media items yet.</Text>
|
||||
: this.state.media.map(mediaItem =>
|
||||
this.renderMediaItem(mediaItem)
|
||||
)}
|
||||
</Stack>
|
||||
</div>
|
||||
|
|
|
@ -178,6 +178,10 @@ export class NavigationItemModal extends React.Component<NavigationItemModalProp
|
|||
}, 300)
|
||||
|
||||
validatePermalink = async (permalink: string): Promise<string> => {
|
||||
if (!permalink) {
|
||||
return URL_REQUIRED_MESSAGE;
|
||||
}
|
||||
|
||||
const isPermalinkNotDefined = await this.permalinkService.isPermalinkDefined(permalink) && !reservedPermalinks.includes(permalink);
|
||||
let errorMessage = validateField(UNIQUE_REQUIRED, permalink, isPermalinkNotDefined);
|
||||
|
||||
|
@ -440,7 +444,7 @@ export class NavigationItemModal extends React.Component<NavigationItemModalProp
|
|||
errors = { [LinkOptionKey.SavedUrl]: errorMessage };
|
||||
} else if (this.state.selectedUrlType === LinkOptionKey.NewUrl) {
|
||||
const errorMessage = await this.validatePermalink(this.state.navItem?.[LinkOptionKey.NewUrl]);
|
||||
errors = { [LinkOptionKey.NewUrl]: errorMessage };
|
||||
if (errorMessage) errors = { [LinkOptionKey.NewUrl]: errorMessage };
|
||||
}
|
||||
} else if (this.state.selectedLinkOption === LinkOptionKey.Media && !this.state.selectedMedia) {
|
||||
errors = { media: 'Please, select a media file' };
|
||||
|
|
|
@ -49,7 +49,7 @@ export class PageDetailsModal extends React.Component<PageDetailsModalProps, Pag
|
|||
}
|
||||
|
||||
onInputChange = async (field: string, newValue: string, validationType?: string): Promise<void> => {
|
||||
let permalink = '';
|
||||
let permalink = null;
|
||||
|
||||
if (!this.props.page && field === 'title') {
|
||||
permalink = newValue.replace(/\s+/g, '-').toLowerCase();
|
||||
|
@ -80,7 +80,7 @@ export class PageDetailsModal extends React.Component<PageDetailsModalProps, Pag
|
|||
errorMessage = validateField(validationType, newValue);
|
||||
}
|
||||
|
||||
if (permalink) {
|
||||
if (permalink !== null) {
|
||||
permalinkErrorMessage = await this.validatePermalink('/' + permalink);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,11 +2,10 @@ import * as React from 'react';
|
|||
import { Resolve } from '@paperbits/react/decorators';
|
||||
import { IPageService, PageContract } from '@paperbits/common/pages';
|
||||
import { ILayoutService, LayoutContract } from '@paperbits/common/layouts';
|
||||
import { Query, Operator } from '@paperbits/common/persistence';
|
||||
import { ViewManager } from '@paperbits/common/ui';
|
||||
import { Router } from '@paperbits/common/routing';
|
||||
import { CommandBarButton, FontIcon, IIconProps, Pivot, PivotItem, SearchBox, Spinner, Stack, Text } from '@fluentui/react';
|
||||
import { getAllValues } from '../utils/helpers';
|
||||
import { createSearchQuery, getAllValues } from '../utils/helpers';
|
||||
import { lightTheme } from '../utils/themes';
|
||||
import { BackButton } from '../utils/components/backButton';
|
||||
import { PageDetailsModal } from './pageDetailsModal';
|
||||
|
@ -78,22 +77,14 @@ export class Pages extends React.Component<PagesProps, PagesState> {
|
|||
}
|
||||
|
||||
searchPages = async (searchPattern: string = ''): Promise<void> => {
|
||||
const query = Query.from().orderBy('title');
|
||||
if (searchPattern) {
|
||||
query.where('title', Operator.contains, searchPattern);
|
||||
}
|
||||
|
||||
const query = createSearchQuery(searchPattern);
|
||||
const pagesSearchResult = await this.pageService.search(query);
|
||||
const allPages = await getAllValues(pagesSearchResult, pagesSearchResult.value);
|
||||
this.setState({ pages: allPages });
|
||||
}
|
||||
|
||||
searchLayouts = async (searchPattern: string = ''): Promise<void> => {
|
||||
const query = Query.from().orderBy('title');
|
||||
if (searchPattern) {
|
||||
query.where('title', Operator.contains, searchPattern);
|
||||
}
|
||||
|
||||
const query = createSearchQuery(searchPattern);
|
||||
const layoutsSearchResult = await this.layoutService.search(query);
|
||||
const allLayouts = await getAllValues(layoutsSearchResult, layoutsSearchResult.value);
|
||||
this.setState({ layouts: allLayouts });
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import * as React from 'react';
|
||||
import { Resolve } from '@paperbits/react/decorators';
|
||||
import { IPopupService, PopupContract } from '@paperbits/common/popups';
|
||||
import { Query, Operator } from '@paperbits/common/persistence';
|
||||
import { ViewManager } from '@paperbits/common/ui';
|
||||
import { CommandBarButton, FontIcon, IIconProps, SearchBox, Spinner, Stack, Text } from '@fluentui/react';
|
||||
import { getAllValues } from '../utils/helpers';
|
||||
import { createSearchQuery, getAllValues } from '../utils/helpers';
|
||||
import { lightTheme } from '../utils/themes';
|
||||
import { BackButton } from '../utils/components/backButton';
|
||||
import { PopupDetailsModal } from './popupDetailsModal';
|
||||
|
@ -54,11 +53,7 @@ export class Popups extends React.Component<PopupsProps, PopupsState> {
|
|||
}
|
||||
|
||||
searchPopups = async (searchPattern: string = ''): Promise<void> => {
|
||||
const query = Query.from().orderBy('title');
|
||||
if (searchPattern) {
|
||||
query.where('title', Operator.contains, searchPattern);
|
||||
}
|
||||
|
||||
const query = createSearchQuery(searchPattern);
|
||||
const popupsSearchResult = await this.popupService.search(query);
|
||||
const allPopups = await getAllValues(popupsSearchResult, popupsSearchResult.value);
|
||||
this.setState({ popups: allPopups });
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import * as React from 'react';
|
||||
import { Resolve } from '@paperbits/react/decorators';
|
||||
import { IUrlService, UrlContract } from '@paperbits/common/urls';
|
||||
import { Query, Operator } from '@paperbits/common/persistence';
|
||||
import { ViewManager } from '@paperbits/common/ui';
|
||||
import { CommandBarButton, FontIcon, IIconProps, SearchBox, Spinner, Stack, Text } from '@fluentui/react';
|
||||
import { getAllValues } from '../utils/helpers';
|
||||
import { createSearchQuery, getAllValues } from '../utils/helpers';
|
||||
import { lightTheme } from '../utils/themes';
|
||||
import { BackButton } from '../utils/components/backButton';
|
||||
import { UrlDetailsModal } from './urlDetailsModal';
|
||||
|
@ -54,11 +53,7 @@ export class Urls extends React.Component<UrlsProps, UrlsState> {
|
|||
}
|
||||
|
||||
searchUrls = async (searchPattern: string = ''): Promise<void> => {
|
||||
const query = Query.from().orderBy('title');
|
||||
if (searchPattern) {
|
||||
query.where('title', Operator.contains, searchPattern);
|
||||
}
|
||||
|
||||
const query = createSearchQuery(searchPattern);
|
||||
const urlsSearchResult = await this.urlService.search(query);
|
||||
const allUrls = await getAllValues(urlsSearchResult, urlsSearchResult.value);
|
||||
this.setState({ urls: allUrls });
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import * as MediaUtils from "@paperbits/common/media/mediaUtils";
|
||||
import { MediaContract } from "@paperbits/common/media";
|
||||
import { Operator, Query } from "@paperbits/common/persistence";
|
||||
|
||||
export const getThumbnailUrl = (mediaItem: MediaContract): string => {
|
||||
if (mediaItem?.mimeType?.startsWith("video")) {
|
||||
|
@ -35,4 +36,14 @@ export const getAllValues = async (page: any, values: any) => {
|
|||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
export const createSearchQuery = (searchPattern: string, fieldName: string = 'title') => {
|
||||
const patternProcessed = searchPattern.replaceAll("#", "%23"); // TODO: Remove this when the issue with # in search is fixed on the Paperbits side
|
||||
const query = Query.from().orderBy(fieldName);
|
||||
if (patternProcessed) {
|
||||
query.where(fieldName, Operator.contains, patternProcessed);
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
Загрузка…
Ссылка в новой задаче