Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add config option for default rendition preset to be applied (KCL-8387) #336

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions lib/config/delivery-configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,9 @@ export interface IDeliveryClientConfig {
* Sets custom domain for assets
*/
assetsDomain?: string;

/**
* Codename of rendition preset to be applied by default to the base asset URL path.
*/
defaultRenditionPreset?: string;
}
13 changes: 9 additions & 4 deletions lib/mappers/element.mapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,19 +251,24 @@ export class ElementMapper {
if (assetContract.renditions) {
renditions = {};

for (const renditionKey of Object.keys(assetContract.renditions)) {
const rendition = assetContract.renditions[renditionKey];
for (const renditionPresetKey of Object.keys(assetContract.renditions)) {
const rendition = assetContract.renditions[renditionPresetKey];

renditions[renditionKey] = {
renditions[renditionPresetKey] = {
...rendition,
url: `${assetUrl}?${rendition.query}` // enhance rendition with absolute url
};
}
}

const renditionToBeApplied: ElementModels.Rendition | null =
(this.config.defaultRenditionPreset && renditions?.[this.config.defaultRenditionPreset]) || null;

const finalUrl = renditionToBeApplied?.url ?? assetUrl;

const asset: ElementModels.AssetModel = {
...assetContract,
url: assetUrl, // use custom url of asset which may contain custom domain
url: finalUrl, // use custom url of asset which may contain custom domain and applied rendition
renditions
};

Expand Down
31 changes: 16 additions & 15 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,21 +143,22 @@ const movieText = response.data.items[0].title.value;

Following is a list of configuration options for DeliveryClient (`IDeliveryClientConfig`):

| Property | type | description |
| ------------------- | :--------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------ |
| projectId | string | ProjectId of your Kontent project |
| elementResolver? | ElementResolver | Element resolver used to map custom elements |
| previewApiKey? | string | Preview API key used to get unpublished content items |
| defaultLanguage? | string | Sets default language that will be used for all queries unless overriden with query parameters |
| proxy? | IDeliveryClientProxyConfig | Can be used to configure custom URLs. Useful when you use reverse proxy or have a need to transform URL - e.g. to remove 'projectId' |
| secureApiKey? | string | Secured API key: Use secured API only when running on Node.JS server, otherwise you can expose your key |
| defaultQueryConfig? | IQueryConfig | Default configuration for all queries. Can be overriden by indidividual queries |
| httpService ? | IHttpService | Can be used to inject custom http service for performing requests |
| globalHeaders? | (queryConfig: IQueryConfig) => IHeader[] | Adds ability to add extra headers to each http request |
| retryStrategy? | IRetryStrategyOptions | Retry strategy configuration |
| linkedItemsReferenceHandler? | LinkedItemsReferenceHandler | Indicates if content items are automatically mapped. Available values: 'map' or 'ignore' |
| propertyNameResolver? | PropertyNameResolver | Used to map properties. Choose one of following default resolvers: `snakeCasePropertyNameResolver`, `pascalCasePropertyNameResolver` & `camelCasePropertyNameResolver` or create your own PropertyNameResolver function |
| assetsDomain? | string | Custom domain for assets. Changes url of assets in both asset & rich text elements |
| Property | type | description |
| ------------------- | :--------------------------------------: |-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| projectId | string | ProjectId of your Kontent project |
| elementResolver? | ElementResolver | Element resolver used to map custom elements |
| previewApiKey? | string | Preview API key used to get unpublished content items |
| defaultLanguage? | string | Sets default language that will be used for all queries unless overriden with query parameters |
| proxy? | IDeliveryClientProxyConfig | Can be used to configure custom URLs. Useful when you use reverse proxy or have a need to transform URL - e.g. to remove 'projectId' |
| secureApiKey? | string | Secured API key: Use secured API only when running on Node.JS server, otherwise you can expose your key |
| defaultQueryConfig? | IQueryConfig | Default configuration for all queries. Can be overriden by indidividual queries |
| httpService ? | IHttpService | Can be used to inject custom http service for performing requests |
| globalHeaders? | (queryConfig: IQueryConfig) => IHeader[] | Adds ability to add extra headers to each http request |
| retryStrategy? | IRetryStrategyOptions | Retry strategy configuration |
| linkedItemsReferenceHandler? | LinkedItemsReferenceHandler | Indicates if content items are automatically mapped. Available values: 'map' or 'ignore' |
| propertyNameResolver? | PropertyNameResolver | Used to map properties. Choose one of following default resolvers: `snakeCasePropertyNameResolver`, `pascalCasePropertyNameResolver` & `camelCasePropertyNameResolver` or create your own PropertyNameResolver function |
| assetsDomain? | string | Custom domain for assets. Changes url of assets in both asset & rich text elements |
| defaultRenditionPreset? | string | Codename of rendition preset to be applied by default to the base asset URL path when present. When set, the SDK will provide the URL of customized images by default. Right now the only supported preset codename is `default`. |

### Create typed models

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"workflow_step": "published"
},
"elements": {
"property1": {
"assetWithRenditionInDefaultPreset": {
"type": "asset",
"name": "Teaser image",
"value": [
Expand All @@ -36,7 +36,7 @@
}
]
},
"property2": {
"assetWithRenditionInMobilePreset": {
"type": "asset",
"name": "Teaser image",
"value": [
Expand All @@ -49,7 +49,7 @@
"width": 640,
"height": 457,
"renditions": {
"default": {
"mobile": {
"rendition_id": "b447ca6c-8020-4e8f-be57-1d110721e535",
"preset_id": "a6d98cd5-8b2c-4e50-99c9-15192bce2490",
"width": 1280,
Expand All @@ -59,8 +59,23 @@
}
}
]
},
"assetWithoutRendition": {
"type": "asset",
"name": "Teaser image",
"value": [
{
"name": "sources.jpg",
"type": "image/jpeg",
"size": 45376,
"description": "Description of what the asset represents.",
"url": "https://assets-us-01.kc-usercontent.com/975bf280-fd91-488c-994c-2f04416e5ee3/3e76909f-599f-4742-b472-77fd4b510e92/sources.jpg",
"width": 640,
"height": 457
}
]
}
}
},
"modular_content": {}
}
}
152 changes: 124 additions & 28 deletions test/browser/isolated-tests/elements/assets/asset-rendition.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,136 @@ import { Elements, IContentItem } from '../../../../../lib';
import { getDeliveryClientWithJson } from '../../../setup';
import * as responseJson from './asset-rendition.spec.json';

describe('Asset rendition', () => {
describe('Asset renditions', () => {
let item: IContentItem;

beforeAll(async () => {
const response = (await getDeliveryClientWithJson(responseJson).item('xx').toPromise());
describe('renditions are correctly set', () => {
beforeAll(async () => {
const response = (await getDeliveryClientWithJson(responseJson).item('xx').toPromise());

item = response.data.item;
item = response.data.item;
});

it(`Asset element without rendition - renditions are null`, () => {
const asset = item.elements.assetWithoutRendition as Elements.AssetsElement;
const image = asset.value[0];
const renditions = image.renditions;

expect(renditions).toBeNull();
});

it(`Asset element with rendition in default preset - renditions should be accessible`, () => {
const asset = item.elements.assetWithRenditionInDefaultPreset as Elements.AssetsElement;
const image = asset.value[0];
const rendition = image.renditions?.default;

const rawImage = responseJson.item.elements.assetWithRenditionInDefaultPreset.value[0];
const rawRendition = rawImage.renditions.default;
expect(rendition?.rendition_id).toEqual(rawRendition.rendition_id);
expect(rendition?.height).toEqual(rawRendition.height);
expect(rendition?.preset_id).toEqual(rawRendition.preset_id);
expect(rendition?.query).toEqual(rawRendition.query);
expect(rendition?.width).toEqual(rawRendition.width);
expect(rendition?.url).toEqual(`${rawImage.url}?${rawRendition.query}`);
});

it(`Asset element with rendition in mobile preset - renditions should be accessible`, () => {
const asset = item.elements.assetWithRenditionInMobilePreset as Elements.AssetsElement;
const image = asset.value[0];
const rendition = image.renditions?.mobile;

const rawImage = responseJson.item.elements.assetWithRenditionInMobilePreset.value[0];
const rawRendition = rawImage.renditions.mobile;
expect(rendition?.height).toEqual(rawRendition.height);
expect(rendition?.preset_id).toEqual(rawRendition.preset_id);
expect(rendition?.query).toEqual(rawRendition.query);
expect(rendition?.width).toEqual(rawRendition.width);
expect(rendition?.url).toEqual(`${rawImage.url}?${rawRendition.query}`);
});
});

it(`Renditions 1 should be accessible`, () => {
const asset = item.elements.property1 as Elements.AssetsElement;
const image = asset.value[0];
const rendition = image.renditions?.default;

const rawRendition = responseJson.item.elements.property1.value[0].renditions.default;
expect(rendition?.rendition_id).toEqual(rawRendition.rendition_id);
expect(rendition?.height).toEqual(rawRendition.height);
expect(rendition?.preset_id).toEqual(rawRendition.preset_id);
expect(rendition?.query).toEqual(rawRendition.query);
expect(rendition?.width).toEqual(rawRendition.width);
expect(rendition?.url).toEqual(`${image.url}?${rawRendition.query}`);
describe('no default profile specified in config', () => {
beforeAll(async () => {
const response = (await getDeliveryClientWithJson(responseJson).item('xx').toPromise());

item = response.data.item;
});

it(`Asset element without rendition - renditions are null`, () => {
const asset = item.elements.assetWithoutRendition as Elements.AssetsElement;
const image = asset.value[0];
const renditions = image.renditions;

const rawImage = responseJson.item.elements.assetWithoutRendition.value[0];
expect(image.url).toEqual(rawImage.url);
expect(renditions).toBeNull();
});

it(`Asset element with rendition in default preset - URL of original asset`, () => {
const asset = item.elements.assetWithRenditionInDefaultPreset as Elements.AssetsElement;
const image = asset.value[0];
const rendition = image.renditions?.default;

const rawImage = responseJson.item.elements.assetWithRenditionInDefaultPreset.value[0];
const rawRendition = rawImage.renditions.default;
expect(image.url).toEqual(rawImage.url);
expect(rendition?.url).toEqual(`${rawImage.url}?${rawRendition.query}`);
});

it(`Asset element with rendition in mobile preset - URL of original asset`, () => {
const asset = item.elements.assetWithRenditionInMobilePreset as Elements.AssetsElement;
const image = asset.value[0];
const rendition = image.renditions?.mobile;

const rawImage = responseJson.item.elements.assetWithRenditionInMobilePreset.value[0];
const rawRendition = rawImage.renditions.mobile;
expect(image.url).toEqual(rawImage.url);
expect(rendition?.url).toEqual(`${rawImage.url}?${rawRendition.query}`);
});
});

it(`Renditions 2 should be accessible`, () => {
const asset = item.elements.property2 as Elements.AssetsElement;
const image = asset.value[0];
const rendition = image.renditions?.default;

const rawRendition = responseJson.item.elements.property2.value[0].renditions.default;
expect(rendition?.rendition_id).toEqual(rawRendition.rendition_id);
expect(rendition?.height).toEqual(rawRendition.height);
expect(rendition?.preset_id).toEqual(rawRendition.preset_id);
expect(rendition?.query).toEqual(rawRendition.query);
expect(rendition?.width).toEqual(rawRendition.width);
expect(rendition?.url).toEqual(`${image.url}?${rawRendition.query}`);
describe('with default preset specified in config', () => {
beforeAll(async () => {
const response = (await getDeliveryClientWithJson(responseJson, {
defaultRenditionPreset: 'default',
projectId: 'x'
}).item('xx').toPromise());

item = response.data.item;
});

it(`Asset element without rendition - URL of original asset`, () => {
const asset = item.elements.assetWithoutRendition as Elements.AssetsElement;
const image = asset.value[0];
const renditions = image.renditions;

const rawImage = responseJson.item.elements.assetWithoutRendition.value[0];
expect(image.url).toEqual(rawImage.url);
expect(renditions).toBeNull();
});

it(`Asset element with rendition in default preset - URL including rendition query string`, () => {
const asset = item.elements.assetWithRenditionInDefaultPreset as Elements.AssetsElement;
const image = asset.value[0];
const rendition = image.renditions?.default;

const rawImage = responseJson.item.elements.assetWithRenditionInDefaultPreset.value[0];
const rawRendition = rawImage.renditions.default;
console.log(image.url, rawImage.url, rawRendition.query);

expect(image.url).toEqual(`${rawImage.url}?${rawRendition.query}`);
expect(rendition?.url).toEqual(`${rawImage.url}?${rawRendition.query}`);
});

it(`Asset element with rendition in mobile preset - URL of original asset`, () => {
const asset = item.elements.assetWithRenditionInMobilePreset as Elements.AssetsElement;
const image = asset.value[0];
const rendition = image.renditions?.mobile;

const rawImage = responseJson.item.elements.assetWithRenditionInMobilePreset.value[0];
const rawRendition = rawImage.renditions.mobile;
expect(image.url).toEqual(rawImage.url);
expect(rendition?.url).toEqual(`${rawImage.url}?${rawRendition.query}`);
});
});
});