Skip to content

Commit

Permalink
feat: add max-slug-length property to instance paramaters
Browse files Browse the repository at this point in the history
  • Loading branch information
Roehl, Johann (extern) committed Dec 8, 2022
1 parent 3615641 commit b678203
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 19 deletions.
36 changes: 25 additions & 11 deletions packages/slug/src/SlugEditor.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import identity from 'lodash/identity';
import { render, configure, cleanup, wait, fireEvent } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import { SlugEditor } from './SlugEditor';
import { CF_GENERATED_SLUG_MAX_LENGTH } from './services/slugify';
import { createFakeFieldAPI, createFakeLocalesAPI } from '@contentful/field-editor-test-utils';

configure({
Expand Down Expand Up @@ -453,21 +454,34 @@ describe('SlugEditor', () => {
});
});

it('slug suggestion is limited to 75 symbols', async () => {
const { field, sdk } = createMocks({
field: '',
titleField: '',
});
[undefined, 0, 100].forEach((maxSlugLength) => {
it(`slug suggestion is limited to ${
maxSlugLength || `${CF_GENERATED_SLUG_MAX_LENGTH} (default)`
} symbols`, async () => {
const { field, sdk } = createMocks({
field: '',
titleField: '',
});

render(<SlugEditor field={field} baseSdk={sdk as any} isInitiallyDisabled={false} />);
render(
<SlugEditor
field={field}
baseSdk={sdk as any}
isInitiallyDisabled={false}
parameters={{ instance: { maxSlugLength } }}
/>
);

await wait();
await wait();

await sdk.entry.fields['title-id'].setValue('a'.repeat(80));
await wait();
await sdk.entry.fields['title-id'].setValue(
'a'.repeat((maxSlugLength ?? CF_GENERATED_SLUG_MAX_LENGTH) + 10)
);
await wait();

const expectedSlug = 'a'.repeat(75);
expect(field.setValue).toHaveBeenLastCalledWith(expectedSlug);
const expectedSlug = 'a'.repeat(maxSlugLength ?? CF_GENERATED_SLUG_MAX_LENGTH);
expect(field.setValue).toHaveBeenLastCalledWith(expectedSlug);
});
});

it('slug suggestion does not contain cut-off words', async () => {
Expand Down
4 changes: 4 additions & 0 deletions packages/slug/src/SlugEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface SlugEditorProps {
parameters?: {
instance: {
trackingFieldId?: string;
maxSlugLength?: number;
};
};
}
Expand Down Expand Up @@ -50,6 +51,7 @@ function FieldConnectorCallback({
locale: FieldAPI['locale'];
createdAt: string;
performUniqueCheck: (value: string) => Promise<boolean>;
maxSlugLength?: number;
}) {
// it is needed to silent permission errors
// this happens when setValue is called on a field which is disabled for permission reasons
Expand Down Expand Up @@ -90,6 +92,7 @@ export function SlugEditor(props: SlugEditorProps) {
}

const trackingFieldId = parameters?.instance?.trackingFieldId ?? undefined;
const maxSlugLength = parameters?.instance?.maxSlugLength ?? undefined;
const entrySys = entry.getSys();

const isLocaleOptional = locales.optional[field.locale];
Expand Down Expand Up @@ -149,6 +152,7 @@ export function SlugEditor(props: SlugEditorProps) {
createdAt={entrySys.createdAt}
locale={field.locale}
performUniqueCheck={performUniqueCheck}
maxSlugLength={maxSlugLength}
key={`slug-editor-${externalReset}`}
/>
);
Expand Down
11 changes: 7 additions & 4 deletions packages/slug/src/SlugEditorField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ interface SlugEditorFieldProps {
createdAt: string;
setValue: (value: string | null | undefined) => void;
performUniqueCheck: (value: string) => Promise<boolean>;
maxSlugLength?: number;
}

type CheckerState = 'checking' | 'unique' | 'duplicate';

function useSlugUpdater(props: SlugEditorFieldProps, check: boolean) {
const { value, setValue, createdAt, locale, titleValue, isOptionalLocaleWithFallback } = props;
const { value, setValue, createdAt, locale, titleValue, isOptionalLocaleWithFallback, maxSlugLength } = props;

React.useEffect(() => {
if (check === false) {
Expand All @@ -32,11 +33,12 @@ function useSlugUpdater(props: SlugEditorFieldProps, check: boolean) {
isOptionalLocaleWithFallback,
locale,
createdAt,
maxSlugLength
});
if (newSlug !== value) {
setValue(newSlug);
}
}, [value, titleValue, isOptionalLocaleWithFallback, check, createdAt, locale, setValue]);
}, [value, titleValue, isOptionalLocaleWithFallback, check, createdAt, locale, setValue, maxSlugLength]);
}

function useUniqueChecker(props: SlugEditorFieldProps) {
Expand Down Expand Up @@ -111,16 +113,17 @@ export function SlugEditorFieldStatic(
}

export function SlugEditorField(props: SlugEditorFieldProps) {
const { titleValue, isOptionalLocaleWithFallback, locale, createdAt, value } = props;
const { titleValue, isOptionalLocaleWithFallback, locale, createdAt, value, maxSlugLength } = props;

const areEqual = React.useCallback(() => {
const potentialSlug = makeSlug(titleValue, {
isOptionalLocaleWithFallback: isOptionalLocaleWithFallback,
locale: locale,
createdAt: createdAt,
maxSlugLength
});
return value === potentialSlug;
}, [titleValue, isOptionalLocaleWithFallback, locale, createdAt, value]);
}, [titleValue, isOptionalLocaleWithFallback, locale, createdAt, value, maxSlugLength]);

const [check, setCheck] = React.useState<boolean>(() => {
if (props.value) {
Expand Down
3 changes: 2 additions & 1 deletion packages/slug/src/services/makeSlug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ type MakeSlugOptions = {
locale: string;
isOptionalLocaleWithFallback: boolean;
createdAt: string;
maxSlugLength?: number;
};

function formatTwoDigit(num: number) {
Expand Down Expand Up @@ -32,5 +33,5 @@ function untitledSlug({ isOptionalLocaleWithFallback, createdAt }: MakeSlugOptio
}

export function makeSlug(title: string | null | undefined, options: MakeSlugOptions) {
return title ? slugify(title, options.locale) : untitledSlug(options);
return title ? slugify(title, options.locale, options.maxSlugLength) : untitledSlug(options);
}
7 changes: 4 additions & 3 deletions packages/slug/src/services/slugify.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import getSlug from 'speakingurl';

const CF_GENERATED_SLUG_MAX_LENGTH = 75;
export const CF_GENERATED_SLUG_MAX_LENGTH = 75;

const languages = [
'ar',
Expand Down Expand Up @@ -51,13 +51,14 @@ function supportedLanguage(locale: string) {
*
* @param {string} text To be turned into a slug.
* @param {string?} locale
* @param {number?} maxLength
* @returns {string} Slug for provided text.
*/
export function slugify(text: string, locale = 'en') {
export function slugify(text: string, locale = 'en', maxLength = CF_GENERATED_SLUG_MAX_LENGTH) {
return getSlug(text, {
separator: '-',
lang: supportedLanguage(locale) || 'en',
truncate: CF_GENERATED_SLUG_MAX_LENGTH + 1,
truncate: maxLength + 1,
custom: {
"'": '',
'`': '',
Expand Down

0 comments on commit b678203

Please sign in to comment.