From 9890e2352ec867a108a5988bb66985ed19348227 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tarje=20S=C3=A6len=20Lavik?= <tarje.lavik@gmail.com>
Date: Tue, 27 Apr 2021 14:58:29 +0200
Subject: [PATCH] Add KulturNav import of Concepts

---
 .../src/kulturnav/SearchKulturnav.js          | 46 ++++-----
 .../import-tool/src/kulturnav/apis/index.js   | 87 +++++++----------
 .../components/{Preview.js => Card.js}        | 93 ++++++++++++-------
 .../import-tool/src/marcus/apis/index.js      |  2 -
 studio/plugins/import-tool/src/nb/SearchNB.js |  2 +-
 .../import-tool/src/nb/components/Card.js     |  2 +-
 6 files changed, 121 insertions(+), 111 deletions(-)
 rename studio/plugins/import-tool/src/kulturnav/components/{Preview.js => Card.js} (75%)

diff --git a/studio/plugins/import-tool/src/kulturnav/SearchKulturnav.js b/studio/plugins/import-tool/src/kulturnav/SearchKulturnav.js
index fb96ede..16b6163 100644
--- a/studio/plugins/import-tool/src/kulturnav/SearchKulturnav.js
+++ b/studio/plugins/import-tool/src/kulturnav/SearchKulturnav.js
@@ -1,33 +1,36 @@
 /* eslint-disable no-undef */
 import React, {useReducer, useEffect} from 'react'
-import ReactPaginate from 'react-paginate'
+//import ReactPaginate from 'react-paginate'
 // import fetch from 'unfetch'
-import Preview from './components/Preview'
+import Card from './components/Card'
 import Search from './components/Search'
-import styles from '../ImportTool.css'
+// import styles from '../ImportTool.css'
 import {searchReducer} from './reducers/searchReducer'
 import {chooseItem} from './apis'
 import {Box, Container, Grid, Flex, Text} from '@sanity/ui'
 
 const IMPORT_API_URL = 'https://kulturnav.org/api/search/'
+const GET_TYPES = 'Concept'
 
 export const initialState = {
-  sourceAPI: 'nb',
-  apiURL: 'https://kulturnav.org/api/search/',
+  sourceAPI: 'kn',
+  apiURL: IMPORT_API_URL,
   loading: true,
-  searchParameter: '',
+  searchParameter: '*',
   items: [],
   page: 0,
   totalElements: 0,
-  limit: 30,
+  max: 64,
   errorMessage: null,
 }
 
 const SearchNB = () => {
   const [state, dispatch] = useReducer(searchReducer, initialState)
 
-  /* useEffect(() => {
-    fetch(state.apiURL + new URLSearchParams({}))
+  useEffect(() => {
+    fetch(
+      `${state.apiURL}actualEntityType:${GET_TYPES},compoundName:${state.searchParameter}/${state.page}/${state.max}`
+    )
       .then((response) => response.json())
       .then((jsonResponse) => {
         dispatch({
@@ -36,9 +39,9 @@ const SearchNB = () => {
           totalElements: jsonResponse.length,
         })
       })
-  }, []) */
+  }, [])
 
-  const handlePageClick = (data) => {
+  /* const handlePageClick = (data) => {
     let selected = data.selected
     let page = selected
 
@@ -48,7 +51,7 @@ const SearchNB = () => {
     })
 
     fetch(
-      state.apiURL + 'actualEntityType:Person%20OR%20Concept,compoundName:' + state.searchParameter
+      state.apiURL + 'actualEntityType:${GET_TYPES},compoundName:' + state.searchParameter
         ? state.searchParameter
         : '' + new URLSearchParams({}),
     )
@@ -68,7 +71,7 @@ const SearchNB = () => {
           })
         }
       })
-  }
+  } */
 
   const search = (searchValue) => {
     // setSearchParameter(searchValue)
@@ -79,10 +82,7 @@ const SearchNB = () => {
     })
 
     fetch(
-      IMPORT_API_URL +
-        'actualEntityType:Person%20OR%20Concept,compoundName:' +
-        searchValue +
-        new URLSearchParams({}),
+      `${state.apiURL}actualEntityType:${GET_TYPES},compoundName:${searchValue}/0/${state.max}`
     )
       .then((response) => response.json())
       .then((jsonResponse) => {
@@ -102,8 +102,8 @@ const SearchNB = () => {
       })
   }
 
-  const {searchParameter, items, totalElements, page, limit, errorMessage, loading} = state
-  console.log(items)
+  const {searchParameter, items, totalElements, page, max, errorMessage, loading} = state
+  
   return (
     <Container width={5} paddingY={5}>
       <form>
@@ -115,13 +115,13 @@ const SearchNB = () => {
         <Text flex={1} size={1}>{totalElements} result found</Text>
       </Box>
 
-      <Box marginBottom={3}>
+      {/* <Box marginBottom={3}>
         <ReactPaginate
           previousLabel={'previous'}
           nextLabel={'next'}
           breakLabel={'...'}
           forcePage={page}
-          pageCount={totalElements / limit}
+          pageCount={totalElements / max}
           marginPagesDisplayed={2}
           pageRangeDisplayed={3}
           containerClassName={styles.pagination}
@@ -132,7 +132,7 @@ const SearchNB = () => {
           activeClassName={styles.active}
           onPageChange={handlePageClick}
         />
-      </Box>
+      </Box> */}
       <Grid columns={[3, 4, 4, 4]} gap={[1, 1, 2, 3]}>
         {loading && !errorMessage ? (
           <span>loading... </span>
@@ -140,7 +140,7 @@ const SearchNB = () => {
           <div className="errorMessage">{errorMessage}</div>
         ) : (
           items.map((item) => (
-            <Preview key={item.id} item={item} searchValue={searchParameter} onClick={chooseItem} />
+            <Card key={item.uuid} item={item} searchValue={searchParameter} onClick={chooseItem} />
           ))
         )}
       </Grid>
diff --git a/studio/plugins/import-tool/src/kulturnav/apis/index.js b/studio/plugins/import-tool/src/kulturnav/apis/index.js
index c8551b5..4993389 100644
--- a/studio/plugins/import-tool/src/kulturnav/apis/index.js
+++ b/studio/plugins/import-tool/src/kulturnav/apis/index.js
@@ -1,58 +1,36 @@
 import {nanoid} from 'nanoid'
-import {mapMediatypes} from './mapMediatypes'
 import sanityClient from 'part:@sanity/base/client'
 
 const client = sanityClient.withConfig({apiVersion: '2021-03-25'})
 
 export const chooseItem = async (item) => {
-  // Get a 200x200px thumbnail. Maybe change to a bigger size based on thumbnail_custom.
-  const imageUrl = item._links.thumbnail_custom.href
-
-  function customImageSize(image, h, w) {
-    if (!image) {
-      console.error('No image input')
-      throw Error
-    }
-    const height = '600' || h
-    const width = '600' || w
-    const template = image.replace('{height}', height).replace('{width}', width)
-    return template
-  }
-
-  const types = mapMediatypes(item.metadata.mediaTypes)
-
   const doc = {
-    _type: 'HumanMadeObject',
-    _id: `${item.id}`,
+    _type: 'Concept',
+    _id: `${item.uuid}`,
     accessState: 'open',
     editorialState: 'published',
-    license:
-      item.accessInfo && item.accessInfo.isPublicDomain
-        ? 'https://creativecommons.org/publicdomain/mark/1.0/'
-        : 'https://rightsstatements.org/vocab/CNE/1.0/',
-    label: item.metadata.title,
-    preferredIdentifier: item.id,
+    label: {
+      ...(item.caption.no ? {
+        nor: item.caption.no
+      } : null),
+      ...(item.caption.sv ? {
+        swe: item.caption.sv
+      } : null)
+    },
+    /* preferredIdentifier: item.uuid,
     identifiedBy: [
       {
         _type: 'Identifier',
         _key: nanoid(),
-        content: item.id,
+        content: item.uuid,
         hasType: {
           _type: 'reference',
           _key: nanoid(),
           _ref: 'de22df48-e3e7-47f2-9d29-cae1b5e4d728',
         },
       },
-    ],
-    hasCurrentOwner: [
-      {
-        _type: 'reference',
-        _key: nanoid(),
-        _ref: '37f7376a-c635-420b-8ec6-ec0fd4c4a55c',
-      },
-    ],
-    subjectOfManifest: item._links.presentation.href,
-    hasType: types,
+    ], */
+    /* hasType: types, */
     wasOutputOf: {
       _type: 'DataTransferEvent',
       _key: nanoid(),
@@ -68,14 +46,14 @@ export const chooseItem = async (item) => {
         _type: 'DigitalDevice',
         _key: nanoid(),
         /* _ref: nanoid(36), */
-        label: 'api.nb.no',
+        label: 'kulturnav.no/api',
       },
     },
   }
 
   /* TODO
     Important to include iiif manifest in asset metadata as the asset could be reused else where in the dataset */
-  const assetMeta = {
+  /* const assetMeta = {
     source: {
       // The source this image is from
       name: 'nb.no',
@@ -86,7 +64,7 @@ export const chooseItem = async (item) => {
     },
     description: item.metadata.title,
     creditLine: 'From nb.no',
-  }
+  } */
 
   const getImageBlob = async (url) => {
     // eslint-disable-next-line no-undef
@@ -151,11 +129,20 @@ export const chooseItem = async (item) => {
   }
 
   const createDoc = async (doc) => {
-    const res = client.createIfNotExists(doc).then((result) => {
-      console.log(`${result._id} was imported!`)
-      return result
-    })
-    return res
+    const transaction = client.transaction()
+  
+    transaction.createOrReplace(doc)
+    
+    transaction
+      .commit()
+      .then((res) => {
+        console.log(JSON.stringify(res, null, 2))
+        return res
+      })
+      .catch((err) => {
+        console.log('Transaction failed', err)
+        return err
+      })
   }
 
   const setAssetRef = async (docID, assetID) => {
@@ -180,23 +167,21 @@ export const chooseItem = async (item) => {
   }
 
   try {
-    const imageResonse = await getImageBlob(customImageSize(imageUrl))
+    /* const imageResonse = await getImageBlob(customImageSize(imageUrl))
     const asset = await uploadImageBlob(imageResonse)
-    await patchAssetMeta(asset._id, assetMeta)
+    await patchAssetMeta(asset._id, assetMeta) */
 
-    const document = await createDoc(doc)
-    if (asset && document) {
+    await createDoc(doc)
+    /* if (asset && document) {
       await setAssetRef(document._id, asset._id)
-    }
+    } */
 
     return {
       success: true,
-      body: JSON.stringify(document, asset),
     }
   } catch (err) {
     return {
       success: false,
-      body: JSON.stringify(response.status, response.statusText),
     }
   }
 }
diff --git a/studio/plugins/import-tool/src/kulturnav/components/Preview.js b/studio/plugins/import-tool/src/kulturnav/components/Card.js
similarity index 75%
rename from studio/plugins/import-tool/src/kulturnav/components/Preview.js
rename to studio/plugins/import-tool/src/kulturnav/components/Card.js
index 1dffe17..df0bb68 100644
--- a/studio/plugins/import-tool/src/kulturnav/components/Preview.js
+++ b/studio/plugins/import-tool/src/kulturnav/components/Card.js
@@ -1,11 +1,18 @@
 import React, {useState} from 'react'
-import Button from 'part:@sanity/components/buttons/default'
-import Card from 'part:@sanity/components/previews/card'
-import DefaultBadge from 'part:@sanity/components/badges/default'
-import DateBadge from '../../components/DateBadge'
-import styled, {keyframes} from 'styled-components'
+import {
+  Box,
+  Card as SanityCard,
+  Heading,
+  Text,
+  Badge,
+  Button,
+  Inline,
+  Stack
+} from '@sanity/ui'
+import {RiDownloadLine} from 'react-icons/ri'
+import {chooseItem} from '../apis'
 
-const Preview = ({item, searchValue, onClick}) => {
+const Card = ({item}) => {
   const [isFetching, setIsFetching] = useState(false)
   const [isImported, setIsImported] = useState(false)
   const [buttonLabel, setButtonLabel] = useState('Import')
@@ -13,12 +20,11 @@ const Preview = ({item, searchValue, onClick}) => {
   const onChooseItem = async (item) => {
     setIsFetching(true)
     setButtonLabel('...importing')
-    const importStatus = await onClick(item)
+    const importStatus = await chooseItem(item)
 
     if (!importStatus.success) {
       setIsFetching(false)
       setButtonLabel('Import failed!')
-      console.log(importStatus.body)
       return
     }
 
@@ -28,10 +34,52 @@ const Preview = ({item, searchValue, onClick}) => {
   }
 
   return (
+    <SanityCard style={{display: "flex", flexDirection: "column"}} key={item._uuid} padding={[2, 2, 3]} radius={2} shadow={1}>
+      {/* NOT EASILY AVAILABLE
+      <Box>
+        <img style={{width: "100%"}} src={item.hasThumbnail} />
+      </Box> */}
+      <Box style={{flexGrow: "1"}} marginY={3}>
+        <Heading size="1">
+          {item.caption.no || item.caption.sv || 'Manglende caption?'}
+        </Heading>
+        <Stack paddingY={2} space={3}>
+          <Inline space={2}>
+            <Badge tone="primary">{item.entityType}</Badge>
+          </Inline>
+          {item.description && (
+            <Text muted size={[1, 1, 2]}>
+              {item.description}
+            </Text>
+          )}
+        </Stack>
+      </Box>
+      <Stack style={{marginTop: "auto"}} style={{borderTop: "1px dotted gray"}} paddingTop={2} space={3}>
+        <Inline space={2}>
+          <Button
+            fontSize={[1, 1, 2]}
+            padding={[1, 1, 2]}
+            icon={RiDownloadLine}
+            text={buttonLabel}
+            mode={isImported ? 'ghost' : 'default'}
+            disabled={isFetching}
+            onClick={() => onChooseItem(item)}
+          />
+          <a href={`https://kulturnav.org/${item.uuid}`} target="_blank" rel="noopener noreferrer">Ã…pne i Kulturnav</a>
+        </Inline>
+      </Stack>
+    </SanityCard>
+  )
+}
+
+export default Card
+
+
+/*   return (
     <Container key={item.uuid}>
       <Card
         title={item.caption.no}
-        /* media={() => (
+        media={() => (
           <img
             src={
               item && item._links && item._links.thumbnail_large
@@ -39,7 +87,7 @@ const Preview = ({item, searchValue, onClick}) => {
                 : 'data:image/png;base64,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'
             }
           />
-        )} */
+        )}
       >
         <p>
           {item.mediaTypes &&
@@ -54,26 +102,5 @@ const Preview = ({item, searchValue, onClick}) => {
           View at Kulturnav
         </a>
       </Card>
-    </Container>
-  )
-}
-
-const FadeIn = keyframes` 
-  0% {
-      opacity: 0;
-  }
-  100% {
-      opacity: 1;
-  }
-`
-
-const Container = styled.div`
-  display: flex;
-  flex-flow: column;
-  width: 300px;
-  padding: 6px 0;
-  margin: 6px;
-  animation: ${FadeIn} 1.2s cubic-bezier(0.39, 0.575, 0.565, 1) both;
-`
-
-export default Preview
+    </Container> */
+  
\ No newline at end of file
diff --git a/studio/plugins/import-tool/src/marcus/apis/index.js b/studio/plugins/import-tool/src/marcus/apis/index.js
index 304ca04..d246abc 100644
--- a/studio/plugins/import-tool/src/marcus/apis/index.js
+++ b/studio/plugins/import-tool/src/marcus/apis/index.js
@@ -54,8 +54,6 @@ export const chooseItem = async (uri) => {
     // Map type to Sanity types
     const types = mapMediatypes([cleanJSON.type])
 
-    /* TODO
-    Include iiif manifest in asset metadata as the asset could be reused elsewhere in the dataset */
     const assetMeta = {
       source: {
         // The source this image is from
diff --git a/studio/plugins/import-tool/src/nb/SearchNB.js b/studio/plugins/import-tool/src/nb/SearchNB.js
index 0b0066e..ef26f5d 100644
--- a/studio/plugins/import-tool/src/nb/SearchNB.js
+++ b/studio/plugins/import-tool/src/nb/SearchNB.js
@@ -157,7 +157,7 @@ const SearchNB = () => {
           <div className="errorMessage">{errorMessage}</div>
         ) : (
           items.map((item) => (
-            <Card key={item._id} item={item} searchValue={searchParameter} onClick={chooseItem} />
+            <Card key={item.id} item={item} searchValue={searchParameter} onClick={chooseItem} />
           ))
         )}
       </Grid>
diff --git a/studio/plugins/import-tool/src/nb/components/Card.js b/studio/plugins/import-tool/src/nb/components/Card.js
index 2ffc5d2..319c4c8 100644
--- a/studio/plugins/import-tool/src/nb/components/Card.js
+++ b/studio/plugins/import-tool/src/nb/components/Card.js
@@ -29,7 +29,7 @@ const Card = ({item, searchValue, onClick}) => {
   return (
     <SanityCard
       style={{display: "flex", flexDirection: "column"}} 
-      key={item._id} 
+      key={item.id}
       padding={[2, 2, 3]} 
       radius={2} 
       shadow={1} 
-- 
GitLab