Skip to content

Commit

Permalink
feat: update fieldMapper to get the whole imageShop data object, rena…
Browse files Browse the repository at this point in the history
…me package to imageshop-org
  • Loading branch information
Petter Kjelkenes committed Aug 31, 2023
1 parent 44b381e commit d1cde90
Show file tree
Hide file tree
Showing 10 changed files with 112 additions and 63 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2023 ImageShop AS
Copyright (c) 2023 Imageshop AS

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
91 changes: 64 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Sanity Asset Source Plugin: ImageShop
# Sanity Asset Source Plugin: Imageshop

Imageshop is a complete Digital Asset Management system (DAM system) for organizing and sharing images, videos and documents. This plugin integrates Imageshop image picker neatly into Sanity, so that you can access all your company's images inside Sanity CMS with only one click. You can also upload photos to Imageshop without leaving Sanity.

Expand All @@ -10,7 +10,7 @@ Imageshop is a complete Digital Asset Management system (DAM system) for organiz
## Installation

```sh
npm install @screentek/sanity-plugin-asset-source-imageshop
npm install @imageshop-org/sanity-plugin-asset-source-imageshop
```

## Usage
Expand All @@ -19,7 +19,7 @@ Add it as a plugin in `sanity.config.ts` (or .js):

```ts
import {defineConfig} from 'sanity'
import {imageShopAsset} from '@screentek/sanity-plugin-asset-source-imageshop'
import {imageShopAsset} from '@imageshop-org/sanity-plugin-asset-source-imageshop'

export default defineConfig({
//...
Expand All @@ -39,19 +39,19 @@ export default defineConfig({
There are many ways to configure the interface for image selection.


| Configuration key | Description | Type | Default value |
| ------------- | ------------- | ---------------- | ----------------- |
| **IMAGESHOPTOKEN** | Required. Token to communicate with imageshop. | string | |
| IMAGE_MAX_SIZE | Max size of the image returned from imageshop to sanity. Format: WxH | string | 2048x2048 |
| IMAGE_ALIAS | Imageshop alias for permalink of image | string | "Large" |
| IMAGESHOPINTERFACENAME | Standard interface used when searching images. | string | |
| IMAGESHOPDOCUMENTPREFIX | Standrad document code prefix used when uploading images. | string | |
| CULTURE | Language for the client. Supports en-US and nb-NO. Norwegian is default (nb-NO) | string | "nb-NO" |
| PROFILEID | Name of a profile, which has to be created by Screentek, which will return several different sizes and aspect ratios. IMAGESHOPSIZE can not be used together with a profile, and showing size dialogue or crop dialogue doens't make sence when using profiles. | string | |
| REQUIREDUPLOADFIELDS | String indicating upload fields which are required, separated by komma. Possible values: name, description, rights, credits, tags | string | |
| UPLOADFIELDLANGUAGES | List of languages which should be shown for name, description etc. Default = no,en. | string | |
| SANITY_ASSET_TEXT_LANGUAGE | What language to store in sanity, from the title, description and credit fields | string | "no" |
| IMAGE_FIELDS_MAPPING | A mapping of IMAGE_SHOP_FIELD_NAME: SANITY_FIELD_NAME. Example: `{"description": "altText", "credits": "credits"}`. Fields will be imported on the image object as extra fields. Useful for e.g. altText. | object:{ string: string } | {} |
| Configuration key | Description | Type | Default value |
| ------------- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ---------------- | ----------------- |
| **IMAGESHOPTOKEN** | Required. Token to communicate with imageshop. | string | |
| IMAGE_MAX_SIZE | Max size of the image returned from imageshop to sanity. Format: WxH | string | 2048x2048 |
| IMAGE_ALIAS | Imageshop alias for permalink of image | string | "Large" |
| IMAGESHOPINTERFACENAME | Standard interface used when searching images. | string | |
| IMAGESHOPDOCUMENTPREFIX | Standrad document code prefix used when uploading images. | string | |
| CULTURE | Language for the client. Supports en-US and nb-NO. Norwegian is default (nb-NO) | string | "nb-NO" |
| PROFILEID | Name of a profile, which has to be created by Imageshop, which will return several different sizes and aspect ratios. IMAGESHOPSIZE can not be used together with a profile, and showing size dialogue or crop dialogue doens't make sence when using profiles. | string | |
| REQUIREDUPLOADFIELDS | String indicating upload fields which are required, separated by komma. Possible values: name, description, rights, credits, tags | string | |
| UPLOADFIELDLANGUAGES | List of languages which should be shown for name, description etc. Default = no,en. | string | |
| SANITY_ASSET_TEXT_LANGUAGE | What language to store in sanity, from the title, description and credit fields | string | "no" |
| IMAGE_FIELDS_MAPPING | A mapping of IMAGE_SHOP_FIELD_NAME: SANITY_FIELD_NAME. Example: `{"description": "altText", "credits": "credits"}`. Fields will be imported on the image object as extra fields. Useful for e.g. altText. | object:{ string: string } | {} |



Expand Down Expand Up @@ -101,7 +101,9 @@ imageShopAsset({
// example:
const currentLanguage = "nb"; // get from localstorage ?

if (currentLanguage == "nb) return "no";
if (currentLanguage == "nb") {
return "no";
}

// Default return some language that is valid.
return "no";
Expand All @@ -117,26 +119,61 @@ If you want to assign custom `fields` on the image object, you can create a cust

```js
imageShopAsset({
// Should return the asset after its transformed.
fieldMapper: (asset, texts) => {
// texts = data from imageshop.
// asset = the sanity image object.
// Should return the sanityAssetDocumentProps after its transformed.
// imageShopData = data from imageshop.
// sanityAssetDocumentProps = the sanity image asset document props
fieldMapper: (sanityAssetDocumentProps, imageShopData) => {
// Do custom mapping of fields here. Example:
console.log({ asset, texts })
console.log({ sanityAssetDocumentProps, imageShopData })

asset.altText = texts.no.title
asset.credits = texts.no.credits
sanityAssetDocumentProps.altText = imageShopData?.text.no.title
sanityAssetDocumentProps.creditLine = imageShopData?.text.no.credits

return asset
return sanityAssetDocumentProps
}
});

```
The **imageShopData** object the image data that is stored in imageshop. The object contains the following data:
```typescript
type ImageShopAsset = {
documentId: string
code: string
extraInfo: null | string
AuthorName: null | string
image: {
file: string
width: number
height: number
thumbnail: string
}
text: {
[k: string]: {
title: string
description: string
rights: string
credits: string
tags: string
categories: string[]
}
}
InterfaceList: Array<{
InterfaceID: number
InterfaceName: string
}>
profile: any
}
```
## License
[MIT](LICENSE) © ImageShop AS
[MIT](LICENSE) © Imageshop AS
## Develop & test
Expand All @@ -146,7 +183,7 @@ imageShopAsset({
npm run link-watch

# in another sanity installation
npx yalc add @screentek/sanity-plugin-asset-source-imageshop && npx yalc link @screentek/sanity-plugin-asset-source-imageshop && npm install
npx yalc add @imageshop-org/sanity-plugin-asset-source-imageshop && npx yalc link @imageshop-org/sanity-plugin-asset-source-imageshop && npm install
```
This plugin uses [@sanity/plugin-kit](https://github.com/sanity-io/plugin-kit)
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "@screentek/sanity-plugin-asset-source-imageshop",
"name": "@imageshop-org/sanity-plugin-asset-source-imageshop",
"version": "1.0.0",
"description": "Imageshop is a complete Digital Asset Management system (DAM system) for organizing and sharing images, videos and documents. This plugin integrates Imageshop image picker neatly into Sanity, so that you can access all your company's images inside Sanity CMS with only one click. You can also upload photos to Imageshop without leaving Sanity.",
"keywords": [
Expand Down
22 changes: 7 additions & 15 deletions src/components/ArrayFunctions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import {Button} from '@sanity/ui'
import {randomKey} from '@sanity/util/content'
import ImageShopAssetSource from './ImageShopAssetSource'
import {ArrayInputFunctionsProps, AssetFromSource, useClient} from 'sanity'
import defaultFieldMapper from '../fieldMapper'
import {useImageShopConfig} from '../context/ImageShopConfigContext'
import {ImageAsset} from 'sanity'

// These are the props any implementation of the ArrayFunctions part will receive
Expand All @@ -21,11 +19,8 @@ const ArrayFunctions = (props: ArrayInputFunctionsProps<{_key: string}, ArraySch
const {onItemAppend} = props
const [isAssetSourceOpen, setIsAssetSourceOpen] = useState(false)
const [isLoading, setIsLoading] = useState(false)
const imageShopConfig = useImageShopConfig()
const client = useClient({apiVersion: '2023-08-08'})

const fieldMapper = imageShopConfig.fieldMapper ? imageShopConfig.fieldMapper : defaultFieldMapper

const handleAddMultipleBtnClick = () => {
setIsAssetSourceOpen(true)
}
Expand Down Expand Up @@ -57,17 +52,14 @@ const ArrayFunctions = (props: ArrayInputFunctionsProps<{_key: string}, ArraySch
const _key = randomKey(12)

// Create object based on sanity datastructure for an image.
const theImage = fieldMapper(
{
_type: 'image',
_key,
asset: {
_type: 'reference',
_ref: imageAssetDocument._id,
},
const theImage = {
_type: 'image',
_key,
asset: {
_type: 'reference',
_ref: imageAssetDocument._id,
},
dataLookup?.texts || {},
)
}

onItemAppend(theImage)
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/ConfigWarning.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const ConfigWarning = () => (
<Text as="h1" weight="semibold">
Missing configuration
</Text>
<Text>You must first configure the plugin with your ImageShop credentials</Text>
<Text>You must first configure the plugin with your Imageshop credentials</Text>
<Text>
Edit the <code>sanity.config.ts/js</code> file in your Sanity Studio folder. And configure
token like so:
Expand Down
26 changes: 18 additions & 8 deletions src/components/ImageShopAssetSource.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {IMAGESHOP_CLIENT, IMAGESHOP_INSERT_IMAGE_API} from '../constants/constan
import {AssetFromSource, AssetSourceComponentProps} from 'sanity'
import {ConfigWarning} from './ConfigWarning'
import {useImageShopConfig} from '../context/ImageShopConfigContext'
import defaultLanguageResolver from '../languageResolver'
import {getIframeParams} from '../util/imageshopUtils'

declare global {
Expand All @@ -30,14 +29,14 @@ const ImageShopAssetSourceInternal = (props: Props) => {
const pluginConfig = useImageShopConfig()
const hasConfig = !!pluginConfig.IMAGESHOPTOKEN
const [loadingMessage, setLoadingMessage] = useState<string | null>(
'Loading ImageShop Media Libary',
'Loading Imageshop Media Libary',
)
const contentRef = useRef<HTMLDivElement>(null)
const domId = useRef(Date.now())
const isMulti = isMultiUploadType
const languageResolver = pluginConfig.languageResolver
? pluginConfig.languageResolver
: () => defaultLanguageResolver(pluginConfig)

const fieldMapper = pluginConfig.fieldMapper

const handleClose = () => {
props.onClose()
Expand All @@ -64,6 +63,10 @@ const ImageShopAssetSourceInternal = (props: Props) => {

const parsedEventData = JSON.parse(imageShopDataString)

const resolvedLanguage = languageResolver
? languageResolver()
: pluginConfig.SANITY_ASSET_TEXT_LANGUAGE || 'no'

if (Array.isArray(parsedEventData)) {
if (!event.data) {
return
Expand All @@ -72,17 +75,24 @@ const ImageShopAssetSourceInternal = (props: Props) => {
if (!imageShopDatas || !Array.isArray(imageShopDatas) || imageShopDatas.length === 0) {
return
}

const assetsToBeUploaded = imageShopDatas
.map((imageShopObject) => imageShopAssetToSanityAsset(imageShopObject, languageResolver))
.map((imageShopData) =>
imageShopAssetToSanityAsset(imageShopData, resolvedLanguage, fieldMapper),
)
.filter((asset) => asset !== null) as AssetFromSource[]

if (assetsToBeUploaded) {
selectedFiles = assetsToBeUploaded
}
} else {
const imageShopData = parsedEventData as ImageShopAsset
// console.log(imageShopData)
const uploadAsset = imageShopAssetToSanityAsset(imageShopData, languageResolver, title)
const uploadAsset = imageShopAssetToSanityAsset(
imageShopData,
resolvedLanguage,
fieldMapper,
title,
)
if (uploadAsset) {
selectedFiles = [uploadAsset]
}
Expand All @@ -106,7 +116,7 @@ const ImageShopAssetSourceInternal = (props: Props) => {
return (
<Dialog
id="imageshop-asset-source"
title="Select image from ImageShop"
title="Select image from Imageshop"
onClose={handleClose}
open
width={hasConfig ? 4 : 1}
Expand Down
7 changes: 4 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ import ImageShop from './components/ImageShopAssetSource'
import Icon from './components/Icon'
import ArrayFunctions from './components/ArrayFunctions'
import {layoutResolver} from './layoutResolver'
import {FieldMapper, LanguageResolver} from './types'

/**
* @public
*/
export const imageShopAssetSource: AssetSource = {
name: 'imageshop',
title: 'ImageShop',
title: 'Imageshop',
component: ImageShop,
icon: Icon,
}
Expand All @@ -32,8 +33,8 @@ export interface ImageShopPluginConfig {
IMAGE_MAX_SIZE?: string

// custom hooks
languageResolver?: () => string
fieldMapper?: (asset: any, documentProps: any) => any
languageResolver?: LanguageResolver
fieldMapper?: FieldMapper
}
/**
* @public
Expand Down
7 changes: 7 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ export type ImageShopAsset = {
categories: string[]
}
}
InterfaceList: Array<{
InterfaceID: number
InterfaceName: string
}>
profile: any
}

export type ImageShopIFrameEventData = [string, string, number, number]
export type FieldMapper = (sanityAssetDocumentProps: any, imageShopData: ImageShopAsset) => any
export type LanguageResolver = () => string
12 changes: 7 additions & 5 deletions src/util/imageShopAssetToSanityAsset.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import {ImageShopAsset} from '../types'
import {FieldMapper, ImageShopAsset} from '../types'
import {AssetFromSource} from 'sanity'

export const imageShopAssetToSanityAsset = (
imageShopData: ImageShopAsset,
languageResolver: () => string,
resolvedLanguage: string,
fieldMapper?: FieldMapper,
documentTitle?: string,
): AssetFromSource | null => {
// Make a check, is this even from imageshop ? Should have .documentId and parsed the first part as json.
if (!imageShopData || !imageShopData.documentId) {
return null
}

const ASSET_TEXT_LANGUAGE = languageResolver()
const textObject = imageShopData.text[ASSET_TEXT_LANGUAGE]
const textObject = imageShopData?.text[resolvedLanguage] || {}
const assetDocumentProps: any = {
_type: 'sanity.imageAsset',
source: {
Expand All @@ -37,7 +37,9 @@ export const imageShopAssetToSanityAsset = (
const asset: AssetFromSource = {
kind: 'url',
value: imageShopData.image.file,
assetDocumentProps: assetDocumentProps,
assetDocumentProps: fieldMapper
? fieldMapper(assetDocumentProps, imageShopData)
: assetDocumentProps,
}
return asset
}

0 comments on commit d1cde90

Please sign in to comment.