diff --git a/.env b/.env index 69f7a67d..37821c4b 100644 --- a/.env +++ b/.env @@ -1 +1,8 @@ NEXT_PUBLIC_BASE_PATH= + +SCHEMA=exhibition +DATABASE_PROVIDER=postgresql +DATABASE_URL=postgres://admin:admin@localhost:5433/exhibition +SPARQL_ENDPOINT=http://localhost:7878/query +SPARQL_ENDPOINT_LABEL=Local Testing +SPARQL_ENDPOINT_PROVIDER=oxigraph diff --git a/.env.example b/.env.example new file mode 100644 index 00000000..a999732f --- /dev/null +++ b/.env.example @@ -0,0 +1,3 @@ +VITE_SPARQL_ENDPOINT=http://localhost:3001 +VITE_SPARQL_ENDPOINT_LABEL=Local Testing +VITE_SPARQL_ENDPOINT_PROVIDER=rest diff --git a/.github/workflows/build-and-push-demo-docker.yml b/.github/workflows/build-and-push-demo-docker.yml new file mode 100644 index 00000000..2470c1f3 --- /dev/null +++ b/.github/workflows/build-and-push-demo-docker.yml @@ -0,0 +1,56 @@ +# +name: Create and publish a Development Demo Docker image + +on: + push: + branches: ['demo'] + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }}-development-demo + +jobs: + build-and-push-image: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - name: Free Disk Space (Ubuntu) + uses: jlumbroso/free-disk-space@main + with: + # this might remove tools that are actually needed, + # when set to "true" but frees about 6 GB + tool-cache: true + - name: Checkout repository + uses: actions/checkout@v4 + - name: Log in to the Container registry + uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Restore and cache Nix store + uses: nix-community/cache-nix-action@v5 + with: + primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix') }} + restore-prefixes-first-match: nix-${{ runner.os }}- + gc-max-store-size-linux: 1081900000 + purge: true + purge-prefixes: cache-${{ runner.os }}- + purge-created: 0 + purge-primary-key: never + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + - name: Build and push Docker image + uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 + with: + context: . + file: ./Dockerfile.demo + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/nextjs.yml b/.github/workflows/nextjs.yml index 2e59aaa0..f13f1eec 100644 --- a/.github/workflows/nextjs.yml +++ b/.github/workflows/nextjs.yml @@ -22,6 +22,7 @@ jobs: # Build job build: runs-on: ubuntu-latest + environment: github-pages steps: - name: Checkout uses: actions/checkout@v4 @@ -57,12 +58,10 @@ jobs: - name: Install dependencies run: bun install - name: create env file - env: - NEXT_PUBLIC_GAPI_OAUTH_CLIENT_ID: ${{ secrets.NEXT_PUBLIC_GAPI_OAUTH_CLIENT_ID }} - NEXT_PUBLIC_BASE_PATH: /${{ github.event.repository.name }} run: | touch ./apps/exhibition-live/.env - echo NEXT_PUBLIC_GAPI_OAUTH_CLIENT_ID="${{ secrets.NEXT_PUBLIC_GAPI_OAUTH_CLIENT_ID }}" >> ./apps/exhibition-live/.env + echo "${{ vars.LOCAL_ENV_FILE }}" > ./apps/exhibition-live/.env + echo NEXT_PUBLIC_GAPI_OAUTH_CLIENT_ID="${{ vars.NEXT_PUBLIC_GAPI_OAUTH_CLIENT_ID }}" >> ./apps/exhibition-live/.env echo NEXT_PUBLIC_BASE_PATH="/${{ github.event.repository.name }}" >> ./apps/exhibition-live/.env - name: Build with Next.js run: bun run build diff --git a/.gitignore b/.gitignore index b6f6a5a4..ab532b49 100644 --- a/.gitignore +++ b/.gitignore @@ -62,3 +62,22 @@ coverage out apps/exhibition-live/exhibition-live + +packages/icons/src/assets/svgs +manifestation/exhibition/typebox +apps/edb-prisma-cli/migrations +apps/edb-prisma-cli/prisma +apps/edb-prisma-cli/prisma +apps/edb-solr-cli/solr +apps/edb-solr-cli/elastic +apps/edb-surreal-api/data +apps/edb-surreal-api/*.AppImage +apps/edb-prisma-cli/schema.prisma + + +.env +/apps/exhibition-live/public/exhibition-corpus-riot.ttl +/apps/edb-solr-cli/export +.aider* +venv/ +.venv/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..43a7bf86 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "packages/edb-sparnatural/jsonschema2shacl"] + path = packages/edb-sparnatural/jsonschema2shacl + url = https://github.com/citiususc/jsonschema2shacl.git + branch = main diff --git a/.prettierignore b/.prettierignore index 74cb3c24..43518f42 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,3 +1,4 @@ /apps/exhibition-live/styles /apps/exhibition-live/public/worker.js /apps/exhibition-live/public/scripts.bundle.js +/apps/edb-solr-cli/solr/solr diff --git a/Dockerfile.demo b/Dockerfile.demo new file mode 100644 index 00000000..8ddfe7b2 --- /dev/null +++ b/Dockerfile.demo @@ -0,0 +1,50 @@ +FROM nixos/nix + +RUN mkdir /app +WORKDIR /app + +COPY flake.nix flake.nix +COPY flake.lock flake.lock + +# Cache some requirements in /nix/store +RUN echo "extra-experimental-features = nix-command flakes" >> /etc/nix/nix.conf +RUN nix develop + + +ENV NEXT_TELEMETRY_DISABLED 1 +ENV NEXT_PUBLIC_BASE_PATH "" + +RUN mkdir -p /home/appuser +RUN nix-shell -p busybox.out --run 'adduser -D -u 1000 appuser && \ + chown -R appuser:appuser /nix && \ + chown -R appuser:appuser /app' + + + +EXPOSE 3000 + +ENV HOSTNAME "0.0.0.0" + + +COPY . /app +RUN chown -R appuser:appuser -R /app + +WORKDIR /app +USER 1000:1000 + +RUN nix develop --command bash -c 'bun i && bun build:packages' + +ENV DATABASE_URL "file:/app/prisma/dev.db" + +RUN nix develop --command bash -c 'bun run build:prisma && \ + bun run prisma:exhibition:generate && \ + prisma migrate dev --name initial --schema ./prisma/exhibition.prisma' + +RUN nix develop --command bash -c 'bun run cli flatImport ./manifestation/exhibition/import/Konvolut_NewYork_2024-07-14.csv -m NewYork -n 10' + +EXPOSE 3001 +EXPOSE 5762 + +COPY ./.env.example /apps/exhibition-live/.env.local + +CMD nix develop --command bash -c 'bun run start' diff --git a/README.md b/README.md index 48f9b6a2..5a3dfa04 100644 --- a/README.md +++ b/README.md @@ -8,20 +8,19 @@ A live demo of the exhibition catalog is available here: [https://slub.github.io You might want to set your own storage backend(s) within the settings modal. -## Storybook stories +## Development Documentation -The pure frontend specific component based framework, that sets the base of the exhibition catalog is documented within the Storybook. - -You can get a live preview of the current `develop` branch here: [https://slub.github.io/exhibition-live/storybook/](https://slub.github.io/exhibition-live/storybook/) +Please have a look at the **[Storybook of the EDB Framework](https://slub.github.io/exhibition-live/storybook/)** for an indepth documentation of the frontend components, th cli +and the overall architecture of the exhibition catalog and the EDB framework. # Development ## Getting Started -First, run the development server: +For a quick start install all dependencies initially build the packages and start the development server of the nextjs exhibition-live application. ```bash -bun i && bun run dev +bun i && bun build:packages && bun run dev:exhibition ``` Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. @@ -56,6 +55,12 @@ Other SPARQL Endpoints, like Jena Fuseki, Virtuoso, Blazegraph or GraphDB can be Additional effort might be needed to configure CORS and authentication and to get along with some Endpoints not beeing fully SPARQL 1.1 compliant. +### Endpoint Configuration + +The configuration of endpoints within the `exhibition-live` application can either be done dynamically at runtime using +the settings modal or by providing a `SPARQL_ENDPOINT` environment variable at build time, which disables setting the endpoint +within the modal and is especially suitable for production deployments, where one wants to make sure all users operate on the same endpoint. + ## Storybook This project uses [Storybooks](https://storybook.js.org/) to enforce reusable component based development and to document them with @@ -68,6 +73,19 @@ bun i && bun run storybook Open [http://localhost:6006](http://localhost:6006) with your browser to see the storybook. +## Testing + +Unit tests of core functionality is done by `jest`. For integration tests of the frontend `Cypress` is being used. + +### Trouble Shooting + +Cypress under Nix: +it might be necessary to delete `~/.cache/Cypress` + +``` +rm -rf ~/.cache/Cypress +``` + ## Using Docker 1. [Install Docker](https://docs.docker.com/get-docker/) on your machine. @@ -130,3 +148,16 @@ that provide additional information for the frontend, like: - the UI-Schemata for form layout and style hints - data mapping declarations for data conversion from and to norm data repositories + +# Helpful Commands + +Complete rebuild without cache: + +``` +docker compose down +docker compose rm -f +docker compose pull +docker compose up --build -d +``` + +Deletes all images, reloads all images from repository, starts all images with building in daemon-mode, may add `docker compose logs -f` for output in following mode. diff --git a/_templates/edb/frontend-package-raw/Component.stories.tsx.t b/_templates/edb/frontend-package-raw/Component.stories.tsx.t new file mode 100644 index 00000000..4692b32a --- /dev/null +++ b/_templates/edb/frontend-package-raw/Component.stories.tsx.t @@ -0,0 +1,39 @@ +--- +to: packages/<%= name.split("/")[1] %>/src/<%= h.changeCase.pascal(name.split("/")[1]) %>.stories.tsx +--- +<% + const packageName = name.split("/")[1]; + const ComponentName = h.changeCase.pascal(packageName); +%> +import React from 'react'; +import { Meta, StoryObj } from '@storybook/react'; +import { <%= ComponentName %>, <%= ComponentName %>Props } from './<%= ComponentName %>'; + +const meta: Meta> = { + component: <%= ComponentName %>, + title: 'Components/<%= ComponentName %>', + argTypes: { + name: { control: 'text' }, + }, +}; + +export default meta; +type Story = StoryObj>; + +export const Default: Story = { + args: { + name: 'World', + }, +}; + +export const CustomName: Story = { + args: { + name: 'Storybook', + }, +}; + +export const LongName: Story = { + args: { + name: 'This is a very long name to test wrapping', + }, +}; diff --git a/_templates/edb/frontend-package-raw/Component.tsx.t b/_templates/edb/frontend-package-raw/Component.tsx.t new file mode 100644 index 00000000..959cdf85 --- /dev/null +++ b/_templates/edb/frontend-package-raw/Component.tsx.t @@ -0,0 +1,15 @@ +--- +to: packages/<%= name.split("/")[1] %>/src/<%= h.changeCase.pascal( name.split("/")[1] ) %>.tsx +--- +<% + const packageName = name.split("/")[1]; + const ComponentName = h.changeCase.pascal(packageName); +%> +import React, {FunctionComponent} from 'react'; + +export type <%= ComponentName %>Props = { + name: string; +}; +export const <%= ComponentName %>: FunctionComponent<<%= ComponentName %>Props> = ({ name }) => { + return
Hello {name} from <%= name %> Package!
; +} diff --git a/_templates/edb/frontend-package-raw/Doc.mdx.t b/_templates/edb/frontend-package-raw/Doc.mdx.t new file mode 100644 index 00000000..fa9c34a9 --- /dev/null +++ b/_templates/edb/frontend-package-raw/Doc.mdx.t @@ -0,0 +1,19 @@ +--- +to: packages/<%= name.split("/")[1] %>/src/<%= h.changeCase.pascal(name.split("/")[1]) %>.mdx +--- +<% + const packageName = name.split("/")[1]; + const ComponentName = h.changeCase.pascal(packageName); +%> +import { Canvas, Meta } from '@storybook/blocks'; +import * as <%= ComponentName %>Stories from './<%= ComponentName %>.stories'; + + + +# <%= ComponentName %> + +<% ["CustomName", "LongName"].forEach((story) => {%> +## <%= story %> +Stories.<%= story %>} /> + +<% }) %> diff --git a/_templates/edb/frontend-package-raw/package.json.t b/_templates/edb/frontend-package-raw/package.json.t new file mode 100644 index 00000000..bb3c5542 --- /dev/null +++ b/_templates/edb/frontend-package-raw/package.json.t @@ -0,0 +1,28 @@ +--- +to: packages/<%= name.split("/")[1] %>/package.json +--- +{ + "name": "<%= name %>", + "version": "1.0.0", + "private": true, + "main": "src/index.tsx", + "types": "src/index.tsx", + "sideEffects": false, + "scripts": { + "typecheck": "tsc -b", + "lint": "eslint \"**/*.ts*\"", + "lint-fix": "eslint --fix \"**/*.ts*\"" + }, + "peerDependencies": { + "@mui/material": "^5", + "@mui/icons-material": "^5", + "react": "^18" + }, + "dependencies": { + }, + "devDependencies": { + "@slub/edb-build-helper": "workspace:*", + "@slub/edb-tsconfig": "workspace:*" + } +} + diff --git a/_templates/edb/frontend-package-raw/prompt.js b/_templates/edb/frontend-package-raw/prompt.js new file mode 100644 index 00000000..8f5cdf63 --- /dev/null +++ b/_templates/edb/frontend-package-raw/prompt.js @@ -0,0 +1,11 @@ +// see types of prompts: +// https://github.com/enquirer/enquirer/tree/master/examples +// +module.exports = [ + { + type: "input", + name: "name", + message: "Name of the sub package", + initial: "@slub/edb-", + }, +]; diff --git a/_templates/edb/frontend-package-raw/src_index.tsx.t b/_templates/edb/frontend-package-raw/src_index.tsx.t new file mode 100644 index 00000000..5ad46c94 --- /dev/null +++ b/_templates/edb/frontend-package-raw/src_index.tsx.t @@ -0,0 +1,4 @@ +--- +to: packages/<%= name.split("/")[1] %>/src/index.tsx +--- +export * from "./<%= h.changeCase.pascal(name.split("/")[1]) %>"; diff --git a/_templates/edb/frontend-package-raw/tsconfig.json.t b/_templates/edb/frontend-package-raw/tsconfig.json.t new file mode 100644 index 00000000..b81af250 --- /dev/null +++ b/_templates/edb/frontend-package-raw/tsconfig.json.t @@ -0,0 +1,12 @@ +--- +to: packages/<%= name.split("/")[1] %>/tsconfig.json +--- +{ + "extends": "@slub/edb-tsconfig/react-library.json", + "include": ["src"], + "exclude": ["dist", "build", "node_modules"], + "compilerOptions": { + "strict": false, + "resolveJsonModule": true + } +} diff --git a/_templates/edb/frontend-package/Component.stories.tsx.t b/_templates/edb/frontend-package/Component.stories.tsx.t new file mode 100644 index 00000000..4692b32a --- /dev/null +++ b/_templates/edb/frontend-package/Component.stories.tsx.t @@ -0,0 +1,39 @@ +--- +to: packages/<%= name.split("/")[1] %>/src/<%= h.changeCase.pascal(name.split("/")[1]) %>.stories.tsx +--- +<% + const packageName = name.split("/")[1]; + const ComponentName = h.changeCase.pascal(packageName); +%> +import React from 'react'; +import { Meta, StoryObj } from '@storybook/react'; +import { <%= ComponentName %>, <%= ComponentName %>Props } from './<%= ComponentName %>'; + +const meta: Meta> = { + component: <%= ComponentName %>, + title: 'Components/<%= ComponentName %>', + argTypes: { + name: { control: 'text' }, + }, +}; + +export default meta; +type Story = StoryObj>; + +export const Default: Story = { + args: { + name: 'World', + }, +}; + +export const CustomName: Story = { + args: { + name: 'Storybook', + }, +}; + +export const LongName: Story = { + args: { + name: 'This is a very long name to test wrapping', + }, +}; diff --git a/_templates/edb/frontend-package/Component.tsx.t b/_templates/edb/frontend-package/Component.tsx.t new file mode 100644 index 00000000..959cdf85 --- /dev/null +++ b/_templates/edb/frontend-package/Component.tsx.t @@ -0,0 +1,15 @@ +--- +to: packages/<%= name.split("/")[1] %>/src/<%= h.changeCase.pascal( name.split("/")[1] ) %>.tsx +--- +<% + const packageName = name.split("/")[1]; + const ComponentName = h.changeCase.pascal(packageName); +%> +import React, {FunctionComponent} from 'react'; + +export type <%= ComponentName %>Props = { + name: string; +}; +export const <%= ComponentName %>: FunctionComponent<<%= ComponentName %>Props> = ({ name }) => { + return
Hello {name} from <%= name %> Package!
; +} diff --git a/_templates/edb/frontend-package/Doc.mdx.t b/_templates/edb/frontend-package/Doc.mdx.t new file mode 100644 index 00000000..fa9c34a9 --- /dev/null +++ b/_templates/edb/frontend-package/Doc.mdx.t @@ -0,0 +1,19 @@ +--- +to: packages/<%= name.split("/")[1] %>/src/<%= h.changeCase.pascal(name.split("/")[1]) %>.mdx +--- +<% + const packageName = name.split("/")[1]; + const ComponentName = h.changeCase.pascal(packageName); +%> +import { Canvas, Meta } from '@storybook/blocks'; +import * as <%= ComponentName %>Stories from './<%= ComponentName %>.stories'; + + + +# <%= ComponentName %> + +<% ["CustomName", "LongName"].forEach((story) => {%> +## <%= story %> +Stories.<%= story %>} /> + +<% }) %> diff --git a/_templates/edb/frontend-package/package.json.t b/_templates/edb/frontend-package/package.json.t new file mode 100644 index 00000000..07ad0fd0 --- /dev/null +++ b/_templates/edb/frontend-package/package.json.t @@ -0,0 +1,38 @@ +--- +to: packages/<%= name.split("/")[1] %>/package.json +--- +{ + "name": "<%= name %>", + "version": "1.0.0", + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.js", + "require": "./dist/index.cjs", + "default": "./dist/index.js", + "types": "./dist/index.d.ts" + } + }, + "scripts": { + "build": "tsup src/index.tsx", + "dev": "tsup src/index.tsx", + "lint": "eslint \"**/*.ts*\"", + "lint-fix": "eslint --fix \"**/*.ts*\"" + }, + "peerDependencies": { + "@mui/material": "^5", + "@mui/icons-material": "^5", + "react": "^18" + }, + "dependencies": { + }, + "devDependencies": { + "@slub/edb-build-helper": "workspace:*", + "@slub/edb-tsconfig": "workspace:*", + "@slub/edb-tsup-config": "workspace:*" + } +} + diff --git a/_templates/edb/frontend-package/prompt.js b/_templates/edb/frontend-package/prompt.js new file mode 100644 index 00000000..8f5cdf63 --- /dev/null +++ b/_templates/edb/frontend-package/prompt.js @@ -0,0 +1,11 @@ +// see types of prompts: +// https://github.com/enquirer/enquirer/tree/master/examples +// +module.exports = [ + { + type: "input", + name: "name", + message: "Name of the sub package", + initial: "@slub/edb-", + }, +]; diff --git a/_templates/edb/frontend-package/src_index.tsx.t b/_templates/edb/frontend-package/src_index.tsx.t new file mode 100644 index 00000000..5ad46c94 --- /dev/null +++ b/_templates/edb/frontend-package/src_index.tsx.t @@ -0,0 +1,4 @@ +--- +to: packages/<%= name.split("/")[1] %>/src/index.tsx +--- +export * from "./<%= h.changeCase.pascal(name.split("/")[1]) %>"; diff --git a/_templates/edb/frontend-package/tsconfig.json.t b/_templates/edb/frontend-package/tsconfig.json.t new file mode 100644 index 00000000..b81af250 --- /dev/null +++ b/_templates/edb/frontend-package/tsconfig.json.t @@ -0,0 +1,12 @@ +--- +to: packages/<%= name.split("/")[1] %>/tsconfig.json +--- +{ + "extends": "@slub/edb-tsconfig/react-library.json", + "include": ["src"], + "exclude": ["dist", "build", "node_modules"], + "compilerOptions": { + "strict": false, + "resolveJsonModule": true + } +} diff --git a/_templates/edb/frontend-package/tsup.config.js.t b/_templates/edb/frontend-package/tsup.config.js.t new file mode 100644 index 00000000..1f057a96 --- /dev/null +++ b/_templates/edb/frontend-package/tsup.config.js.t @@ -0,0 +1,8 @@ +--- +to: packages/<%= name.split("/")[1] %>/tsup.config.js +--- +import { makeConfigWithExternals } from "@slub/edb-tsup-config/tsup.config.js"; +import pkg from "./package.json"; + +const config = makeConfigWithExternals(pkg); +export default config; diff --git a/_templates/edb/manifestation/config.ejs.t b/_templates/edb/manifestation/config.ejs.t new file mode 100644 index 00000000..8b2d7aeb --- /dev/null +++ b/_templates/edb/manifestation/config.ejs.t @@ -0,0 +1,94 @@ +--- +to: apps/exhibition-live/components/config/<%= name %>AppConfig.ts +--- +import { + makeStubSchema, + primaryFields, + primaryFieldExtracts, + schema, +} from "@slub/<%= name %>-schema"; +import { JSONSchema7 } from "json-schema"; +import { makeDefaultUiSchemaForAllDefinitions } from "./makeDefaultUiSchemaForAllDefinitions"; +import { rendererRegistry } from "./rendererRegistry"; +import { materialCells } from "@jsonforms/material-renderers"; +import { IRIToStringFn, SparqlBuildOptions } from "@slub/edb-core-types"; +import { JsonFormsRendererRegistryEntry } from "@jsonforms/core"; +import { primaryTextFieldControlTester, PrimaryTextFieldRenderer } from "../renderer"; +import namespace from "@rdfjs/namespace"; +import { v4 as uuidv4 } from "uuid"; + +const BASE_IRI = "http://ontologies.slub-dresden.de/<%= name %>#"; +const sladb = namespace(BASE_IRI); +const slent = namespace( + "http://ontologies.slub-dresden.de/<%= name %>/entity/", +); + +export const typeIRItoTypeName = (iri: string) => { + return iri?.substring(BASE_IRI.length, iri.length); +}; + +const defaultPrefix = sladb[""].value; +const defaultJsonldContext = { + "@vocab": defaultPrefix, + xs: "http://www.w3.org/2001/XMLSchema#", + image: { + "@type": "xs:anyURI", + }, +}; + +const defaultQueryBuilderOptions: SparqlBuildOptions = { + prefixes: { [""]: sladb[""].value, slent: slent[""].value }, + propertyToIRI: (property: string) => { + return sladb[property].value; + }, + typeIRItoTypeName: typeIRItoTypeName, + primaryFields: primaryFields, + primaryFieldExtracts: primaryFieldExtracts, + sparqlFlavour: "oxigraph", +}; + +const createNewIRI = () => slent(uuidv4()).value; +const primaryFieldsRegistry: ( + typeIRI: string, + typeIRItoTypeName: IRIToStringFn, +) => JsonFormsRendererRegistryEntry[] = (typeIRI, typeIRIToTypeName) => + primaryFields[typeIRIToTypeName(typeIRI)]?.label + ? [ + { + tester: primaryTextFieldControlTester(typeIRIToTypeName(typeIRI)), + renderer: PrimaryTextFieldRenderer, + }, + ] + : []; +const someNameToTypeIRI = (name: string) => sladb(name).value; +const someIRIToTypeName = (iri: string) => + iri?.substring(BASE_IRI.length, iri.length); +export const <%= name %>AppConfig = { + queryBuildOptions: defaultQueryBuilderOptions, + typeNameToTypeIRI: someNameToTypeIRI, + propertyNameToIRI: someNameToTypeIRI, + typeIRIToTypeName: someIRIToTypeName, + propertyIRIToPropertyName: someIRIToTypeName, + createEntityIRI: createNewIRI, + jsonLDConfig: { + defaultPrefix: defaultPrefix, + jsonldContext: defaultJsonldContext, + allowUnsafeSourceIRIs: false, + }, + normDataMapping: { + gnd: { + mapping: [], + typeToTypeMap: {}, + }, + }, + schema: schema as JSONSchema7, + makeStubSchema: makeStubSchema, + uiSchemaDefaultRegistry: makeDefaultUiSchemaForAllDefinitions( + schema as JSONSchema7, + ), + rendererRegistry: rendererRegistry, + cellRendererRegistry: materialCells, + primaryFieldRendererRegistry: (typeIRI: string) => + primaryFieldsRegistry(typeIRI, someIRIToTypeName), + uischemata: undefined, +}; diff --git a/_templates/edb/manifestation/createPrismaSchemal.ejs.t b/_templates/edb/manifestation/createPrismaSchemal.ejs.t new file mode 100644 index 00000000..44c496c6 --- /dev/null +++ b/_templates/edb/manifestation/createPrismaSchemal.ejs.t @@ -0,0 +1,10 @@ +--- +to: manifestation/<%= name %>/src/createPrismaSchemal.ts +--- +import { logPrismaSchemaWithPreamble } from "@slub/json-schema-prisma-utils"; +import { extendSchemaShortcut } from "@slub/json-schema-utils"; +import { schema, schemaName } from "./schema"; + +const extendedSchema = extendSchemaShortcut(schema); + +console.log(logPrismaSchemaWithPreamble(schemaName, extendedSchema)); diff --git a/_templates/edb/manifestation/index.ejs.t b/_templates/edb/manifestation/index.ejs.t new file mode 100644 index 00000000..ba288e5f --- /dev/null +++ b/_templates/edb/manifestation/index.ejs.t @@ -0,0 +1,6 @@ +--- +to: manifestation/<%= name %>/src/index.ts +--- +export * from "./schema"; +export * from "./primaryFields"; +export * from "./makeStubSchema"; diff --git a/_templates/edb/manifestation/makeStubSchema.ejs.t b/_templates/edb/manifestation/makeStubSchema.ejs.t new file mode 100644 index 00000000..3841b186 --- /dev/null +++ b/_templates/edb/manifestation/makeStubSchema.ejs.t @@ -0,0 +1,66 @@ +--- +to: manifestation/<%= name %>/src/makeStubSchema.ts +--- +import { JSONSchema7 } from "json-schema"; +import { + GeneratePropertiesFunction, + prepareStubbedSchema, + SchemaExpander, +} from "@slub/json-schema-utils"; + +export const schemaExpander: SchemaExpander = { + additionalProperties: { + idAuthority: { + title: "Normdatenbeziehung", + type: "object", + properties: { + authority: { + title: "Autorität", + type: "string", + format: "uri", + }, + id: { + title: "IRI", + type: "string", + format: "uri", + }, + }, + }, + }, + options: { + excludeType: [], + excludeSemanticPropertiesForType: ["AuthorityEntry"], + }, +}; +const makeGenSlubJSONLDSemanticProperties: ( + baseIRI: string, + entitytBaseIRI: string, +) => GeneratePropertiesFunction = + (baseIRI: string, entityBaseIRI: string) => (modelName: string) => ({ + "@type": { + const: `${baseIRI}${modelName.replace(/Stub$/, "")}`, + type: "string", + }, + "@id": { + title: entityBaseIRI, + type: "string", + }, + }); + +const genSlubJSONLDSemanticProperties = makeGenSlubJSONLDSemanticProperties( + "http://ontologies.slub-dresden.de/<%= h.changeCase.paramCase(name) %>#", + "http://ontologies.slub-dresden.de/<%= h.changeCase.paramCase(name) %>/entity/", +); +const genSlubRequiredProperties = (_modelName: string) => { + return ["@type", "@id"]; +}; +export const makeStubSchema: (schema: JSONSchema7) => JSONSchema7 = ( + schema, +) => { + return prepareStubbedSchema( + schema, + genSlubJSONLDSemanticProperties, + genSlubRequiredProperties, + schemaExpander.options, + ); +}; diff --git a/_templates/edb/manifestation/package.ejs.t b/_templates/edb/manifestation/package.ejs.t new file mode 100644 index 00000000..0d6d0b60 --- /dev/null +++ b/_templates/edb/manifestation/package.ejs.t @@ -0,0 +1,41 @@ +--- +to: manifestation/<%= name %>/package.json +--- +{ + "name": "@slub/<%= h.changeCase.paramCase(name) %>-schema", + "version": "1.0.0", + "description": "Schema for the <%= name %> database", + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.js", + "require": "./dist/index.cjs", + "default": "./dist/index.js", + "types": "./dist/index.d.ts" + } + }, + "scripts": { + "build": "tsup", + "dev": "tsup --watch", + "schema:export": "bun ./schemas/exportSchema.ts > ./schemas/jsonschema/<%= h.changeCase.pascalCase(name) %>.schema.json", + "build:prisma": "bun ./src/createPrismaSchemal.ts > ../../prisma/<%= h.changeCase.paramCase(name) %>.prisma", + "build:doc": "mkdir -p docs/reference && jsonschema2md -o docs/reference -d schemas/jsonschema", + "build:typebox": "mkdir -p typebox && schema2typebox --input schemas/jsonschema/<%= h.changeCase.pascalCase(name) %>.schema.json --output typebox/generated-typebox.ts" + }, + "devDependencies": { + "@types/rdfjs__namespace": "^2.0.8", + "@slub/json-schema-prisma-utils": "workspace:*", + "@slub/edb-build-helper": "workspace:*", + "@slub/edb-data-mapping": "workspace:*", + "@slub/edb-core-types": "workspace:*", + "json-schema": "^0.4.0", + "@adobe/jsonschema2md": "^7.1.5", + "schema2typebox": "^1.7.5" + }, + "dependencies": { + "@rdfjs/namespace": "^2.0.0" + } +} diff --git a/_templates/edb/manifestation/primaryFields.ejs.t b/_templates/edb/manifestation/primaryFields.ejs.t new file mode 100644 index 00000000..841f276d --- /dev/null +++ b/_templates/edb/manifestation/primaryFields.ejs.t @@ -0,0 +1,35 @@ +--- +to: manifestation/<%= name %>/src/primaryFields.ts +--- +import { + PrimaryField, + PrimaryFieldDeclaration, + PrimaryFieldExtractDeclaration, +} from "@slub/edb-core-types"; + +type <%= h.changeCase.pascalCase(name) %>PrimaryFieldDeclaration = PrimaryFieldDeclaration; + +type <%= h.changeCase.pascalCase(name) %>PrimaryFieldExtractDeclaration = PrimaryFieldExtractDeclaration< + any, + string +>; + +const defaultMapping: PrimaryField = { + label: "title", + description: "description", +}; + +const defaultMappingWithImg: PrimaryField = { + label: "title", + description: "description", + image: "image", +}; + +export const primaryFields: Partial<<%= h.changeCase.pascalCase(name) %>PrimaryFieldDeclaration> = { + <%= h.changeCase.pascalCase(name) %>: defaultMappingWithImg, +}; + +export const primaryFieldExtracts: Partial<<%= h.changeCase.pascalCase(name) %>PrimaryFieldExtractDeclaration> = + { + ...primaryFields, + }; diff --git a/_templates/edb/manifestation/schema.ejs.t b/_templates/edb/manifestation/schema.ejs.t new file mode 100644 index 00000000..75c4c676 --- /dev/null +++ b/_templates/edb/manifestation/schema.ejs.t @@ -0,0 +1,39 @@ +--- +to: manifestation/<%= name %>/src/schema.ts +--- +import { JSONSchema7 } from "json-schema"; +import { extendDefinitionsWithProperties } from "@slub/json-schema-utils"; +import { schemaExpander } from "./makeStubSchema"; + +export const schemaName = "<%= h.changeCase.paramCase(name) %>"; + +const rawSchema: JSONSchema7 = { + $schema: "http://json-schema.org/draft-07/schema#", + $id: "https://schema.adb.arthistoricum.net/<%= h.changeCase.paramCase(name) %>#v1", + title: "SLUB <%= name %> Datenbank", + $defs: { + <%= h.changeCase.pascalCase(name) %>: { + type: "object", + properties: { + title: { + type: "string", + maxLength: 200, + }, + description: { + type: "string", + }, + image: { + type: "string", + format: "uri", + }, + }, + }, + }, +}; + +export const schema = extendDefinitionsWithProperties( + rawSchema, + () => schemaExpander.additionalProperties, + undefined, + schemaExpander.options, +); diff --git a/_templates/edb/manifestation/tsconfig.ejs.t b/_templates/edb/manifestation/tsconfig.ejs.t new file mode 100644 index 00000000..1d047868 --- /dev/null +++ b/_templates/edb/manifestation/tsconfig.ejs.t @@ -0,0 +1,11 @@ +--- +to: manifestation/<%= name %>/tsconfig.json +--- +{ + "extends": "@slub/edb-tsconfig/base.json", + "include": ["./src"], + "exclude": ["dist", "build", "node_modules"], + "compilerOptions": { + "resolveJsonModule": true + } +} diff --git a/_templates/edb/manifestation/tsup.config.ejs.t b/_templates/edb/manifestation/tsup.config.ejs.t new file mode 100644 index 00000000..2c8f9830 --- /dev/null +++ b/_templates/edb/manifestation/tsup.config.ejs.t @@ -0,0 +1,6 @@ +--- +to: manifestation/<%= name %>/tsup.config.js +--- +import config from "@slub/edb-tsup-config/tsup.config.js"; + +export default config; diff --git a/_templates/edb/tsup-package/index.ts.t b/_templates/edb/tsup-package/index.ts.t new file mode 100644 index 00000000..1f97039d --- /dev/null +++ b/_templates/edb/tsup-package/index.ts.t @@ -0,0 +1,4 @@ +--- +to: packages/<%= name.split("/")[1] %>/src/index.ts +--- +console.log('Hello, world!'); diff --git a/_templates/edb/tsup-package/jest.config.js.t b/_templates/edb/tsup-package/jest.config.js.t new file mode 100644 index 00000000..7f0acc8a --- /dev/null +++ b/_templates/edb/tsup-package/jest.config.js.t @@ -0,0 +1,13 @@ +--- +to: packages/<%= name.split("/")[1] %>/jest.config.js +--- +export default { + transform: { + "^.+\\.(ts|tsx)$": [ + "ts-jest", + { + useESM: true, + }, + ], + }, +}; diff --git a/_templates/edb/tsup-package/package.json.t b/_templates/edb/tsup-package/package.json.t new file mode 100644 index 00000000..23bb8820 --- /dev/null +++ b/_templates/edb/tsup-package/package.json.t @@ -0,0 +1,39 @@ +--- +to: packages/<%= name.split("/")[1] %>/package.json +--- +{ + "name": "<%= name %>", + "version": "1.0.0", + "description": "<%= description %>", + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.js", + "require": "./dist/index.cjs", + "default": "./dist/index.js", + "types": "./dist/index.d.ts" + } + }, + "scripts": { + "build": "tsup", + "dev": "tsup --watch", + "lint": "eslint \"**/*.ts*\"", + "lint-fix": "eslint --fix \"**/*.ts*\"", + "test": "jest", + "test:watch": "jest --watch --color", + "test:coverage": "jest --coverage", + "doc": "typedoc" + }, + "devDependencies": { + "@slub/edb-build-helper": "workspace:*", + "@slub/edb-tsconfig": "workspace:*", + "@slub/edb-tsup-config": "workspace:*", + "eslint-config-edb": "workspace:*", + "@types/jest": "^29", + "typescript": "^5" + } +} + diff --git a/_templates/edb/tsup-package/prompt.js b/_templates/edb/tsup-package/prompt.js new file mode 100644 index 00000000..b9b9201f --- /dev/null +++ b/_templates/edb/tsup-package/prompt.js @@ -0,0 +1,16 @@ +// see types of prompts: +// https://github.com/enquirer/enquirer/tree/master/examples +// +module.exports = [ + { + type: "input", + name: "name", + message: "Name of the sub package", + initial: "@slub/edb-", + }, + { + type: "input", + name: "description", + message: "Description of the sub package", + }, +]; diff --git a/_templates/edb/tsup-package/tsconfig.json.t b/_templates/edb/tsup-package/tsconfig.json.t new file mode 100644 index 00000000..37661290 --- /dev/null +++ b/_templates/edb/tsup-package/tsconfig.json.t @@ -0,0 +1,11 @@ +--- +to: packages/<%= name.split("/")[1] %>/tsconfig.json +--- +{ + "extends": "@slub/edb-tsconfig/base.json", + "include": ["."], + "exclude": ["dist", "build", "node_modules"], + "compilerOptions": { + "resolveJsonModule": true + } +} diff --git a/_templates/edb/tsup-package/tsup.config.js.t b/_templates/edb/tsup-package/tsup.config.js.t new file mode 100644 index 00000000..1f057a96 --- /dev/null +++ b/_templates/edb/tsup-package/tsup.config.js.t @@ -0,0 +1,8 @@ +--- +to: packages/<%= name.split("/")[1] %>/tsup.config.js +--- +import { makeConfigWithExternals } from "@slub/edb-tsup-config/tsup.config.js"; +import pkg from "./package.json"; + +const config = makeConfigWithExternals(pkg); +export default config; diff --git a/_templates/edb/tsup-package/typedoc.json.t b/_templates/edb/tsup-package/typedoc.json.t new file mode 100644 index 00000000..43273c1a --- /dev/null +++ b/_templates/edb/tsup-package/typedoc.json.t @@ -0,0 +1,7 @@ +--- +to: packages/<%= name.split("/")[1] %>/typedoc.js +--- +{ + "extends": ["@slub/edb-tsconfig/typedoc.base.json"], + "entryPoints": ["src/index.ts"] +} diff --git a/_templates/generator/help/index.ejs.t b/_templates/generator/help/index.ejs.t new file mode 100644 index 00000000..90a29aff --- /dev/null +++ b/_templates/generator/help/index.ejs.t @@ -0,0 +1,5 @@ +--- +message: | + hygen {bold generator new} --name [NAME] --action [ACTION] + hygen {bold generator with-prompt} --name [NAME] --action [ACTION] +--- \ No newline at end of file diff --git a/_templates/generator/new/hello.ejs.t b/_templates/generator/new/hello.ejs.t new file mode 100644 index 00000000..5680d963 --- /dev/null +++ b/_templates/generator/new/hello.ejs.t @@ -0,0 +1,18 @@ +--- +to: _templates/<%= name %>/<%= action || 'new' %>/hello.ejs.t +--- +--- +to: app/hello.js +--- +const hello = ``` +Hello! +This is your first hygen template. + +Learn what it can do here: + +https://github.com/jondot/hygen +``` + +console.log(hello) + + diff --git a/_templates/generator/with-prompt/hello.ejs.t b/_templates/generator/with-prompt/hello.ejs.t new file mode 100644 index 00000000..ba6abc56 --- /dev/null +++ b/_templates/generator/with-prompt/hello.ejs.t @@ -0,0 +1,18 @@ +--- +to: _templates/<%= name %>/<%= action || 'new' %>/hello.ejs.t +--- +--- +to: app/hello.js +--- +const hello = ``` +Hello! +This is your first prompt based hygen template. + +Learn what it can do here: + +https://github.com/jondot/hygen +``` + +console.log(hello) + + diff --git a/_templates/generator/with-prompt/prompt.ejs.t b/_templates/generator/with-prompt/prompt.ejs.t new file mode 100644 index 00000000..c0cc98ae --- /dev/null +++ b/_templates/generator/with-prompt/prompt.ejs.t @@ -0,0 +1,15 @@ +--- +to: _templates/<%= name %>/<%= action || 'new' %>/prompt.js +--- + +// see types of prompts: +// https://github.com/enquirer/enquirer/tree/master/examples +// +module.exports = [ + { + type: 'input', + name: 'message', + message: "Name of the sub package" + initial: "@slub/edb-" + } +] diff --git a/_templates/init/repo/new-repo.ejs.t b/_templates/init/repo/new-repo.ejs.t new file mode 100644 index 00000000..08e7cffd --- /dev/null +++ b/_templates/init/repo/new-repo.ejs.t @@ -0,0 +1,4 @@ +--- +setup: <%= name %> +force: true # this is because mostly, people init into existing folders is safe +--- diff --git a/apps/edb-api/package.json b/apps/edb-api/package.json index 6febaadf..0db8782c 100644 --- a/apps/edb-api/package.json +++ b/apps/edb-api/package.json @@ -5,10 +5,13 @@ "type": "module", "main": "index.js", "scripts": { - "start": "tsx src/index.ts", + "start": "bun src/index.ts", + "demo": "bun src/index.ts", "start:graphiql": "docker run --name graphiql --rm -p 4000:4000 -e API_URL=http://localhost:3001/graphql npalm/graphiql", - "dev": "tsx watch src/index.ts", - "start:debug": "node --inspect --loader tsx 'src/index.ts'" + "dev": "bun --watch src/index.ts", + "dev:api": "bun run dev", + "start:debug": "bun --inspect 'src/index.ts'", + "build:swagger": "curl http://localhost:3001/swagger/json -o ./swagger.json" }, "keywords": [], "author": "Sebastian Tilsch ", @@ -23,22 +26,25 @@ }, "dependencies": { "@benzene/http": "^0.4.2", - "@elysiajs/cors": "^0.8.0", - "@elysiajs/graphql-yoga": "^0.8.0", + "@elysiajs/cors": "^1.1", + "@elysiajs/graphql-yoga": "^1.1", + "@elysiajs/swagger": "^1.1", "@graphql-tools/schema": "^10.0.3", "@rdfjs/data-model": "^2.0.2", "@rdfjs/namespace": "^2.0.1", "@slub/exhibition-schema": "workspace:*", "@slub/exhibition-sparql-config": "workspace:*", "@slub/sparql-db-impl": "workspace:*", + "@slub/prisma-db-impl": "workspace:*", "@slub/edb-core-utils": "workspace:*", "@slub/edb-graph-traversal": "workspace:*", "@slub/remote-query-implementations": "workspace:*", "@slub/sparql-schema": "workspace:*", "@slub/json-schema-utils": "workspace:*", "@tpluscode/sparql-builder": "^0.3.31", + "qs": "^6.12.3", "cmd-ts": "^0.13.0", - "elysia": "^0.8.17", + "elysia": "^1.1", "graphql": "^16.8.1", "graphql-mobius": "^0.1.13", "graphql-tag": "^2.12.6", diff --git a/apps/edb-api/src/dataStore.ts b/apps/edb-api/src/dataStore.ts index 0461bcf3..6ab55c8c 100644 --- a/apps/edb-api/src/dataStore.ts +++ b/apps/edb-api/src/dataStore.ts @@ -1,26 +1,24 @@ import config from "@slub/exhibition-sparql-config"; -import { oxigraphCrudOptions } from "@slub/remote-query-implementations"; -import { initSPARQLStore } from "@slub/sparql-db-impl"; -import schema from "@slub/exhibition-schema/schemas/jsonschema/Exhibition.schema.json"; -import { JSONSchema7 } from "json-schema"; +import { + getProviderOrDefault, + getSPARQLFlavour, +} from "@slub/remote-query-implementations"; +import { initSPARQLDataStoreFromConfig } from "@slub/sparql-db-impl"; + +const worker = getProviderOrDefault(config.sparqlEndpoint); + +if (!worker) { + throw new Error("No worker found for the given SPARQL endpoint"); +} +export const dataStore = initSPARQLDataStoreFromConfig( + config, + worker(config.sparqlEndpoint), + getSPARQLFlavour(config.sparqlEndpoint), +); -const { - namespace, - walkerOptions, - defaultPrefix, - defaultQueryBuilderOptions, - sparqlEndpoint, -} = config; -const crudOptions = oxigraphCrudOptions(sparqlEndpoint); export const typeNameToTypeIRI = (typeName: string) => - namespace(typeName).value; + config.namespace(typeName).value; -export const dataStore = initSPARQLStore({ - defaultPrefix, - typeNameToTypeIRI, - queryBuildOptions: defaultQueryBuilderOptions, - walkerOptions, - sparqlQueryFunctions: crudOptions, - schema: schema as JSONSchema7, - defaultLimit: 10, -}); +export const typeIRItoTypeName = (iri: string) => { + return iri?.substring(config.BASE_IRI.length, iri.length); +}; diff --git a/apps/edb-api/src/extendSchema.ts b/apps/edb-api/src/extendSchema.ts deleted file mode 100644 index d343c0b5..00000000 --- a/apps/edb-api/src/extendSchema.ts +++ /dev/null @@ -1,61 +0,0 @@ -import namespace from "@rdfjs/namespace"; -import { GenJSONLDSemanticPropertiesFunction } from "@slub/json-schema-utils"; -import { JSONSchema7 } from "json-schema"; -import { - defs, - getDefintitionKey, - withJSONLDProperties, -} from "@slub/json-schema-utils"; - -export const sladb = namespace("http://ontologies.slub-dresden.de/exhibition#"); -export const slent = namespace( - "http://ontologies.slub-dresden.de/exhibition/entity#", -); -const makeSemanticProperties: ( - baseIRI: string, - entitytBaseIRI: string, -) => GenJSONLDSemanticPropertiesFunction = - (baseIRI: string, entityBaseIRI: string) => (modelName: string) => ({ - _type: { - const: `${baseIRI}${modelName}`, - type: "string", - }, - _id: { - title: entityBaseIRI, - type: "string", - }, - }); - -const jsonldSemanticPropertiesFunction = makeSemanticProperties( - sladb[""].value, - slent[""].value, -); -const genRequiredProperties = (_modelName: string) => { - return ["_type", "_id"]; -}; - -export const extendSchema = (schema: any): JSONSchema7 => { - const excludeTypes = ["AuthorityEntry"]; - const definitionsWithJSONLDProperties = Object.entries(defs(schema)).reduce< - JSONSchema7["definitions"] - >((acc, [key, value]) => { - return excludeTypes?.includes(key) - ? { ...acc, [key]: value } - : { - ...acc, - [key]: withJSONLDProperties( - key, - value as JSONSchema7, - jsonldSemanticPropertiesFunction, - genRequiredProperties, - ), - }; - }, {}) as JSONSchema7["definitions"]; - const definitionsKey = getDefintitionKey(schema); - return { - ...schema, - [definitionsKey]: { - ...definitionsWithJSONLDProperties, - }, - }; -}; diff --git a/apps/edb-api/src/index.ts b/apps/edb-api/src/index.ts index 0d3e3ed1..60c2ae09 100644 --- a/apps/edb-api/src/index.ts +++ b/apps/edb-api/src/index.ts @@ -1,35 +1,59 @@ -import { Elysia } from "elysia"; +import Elysia, { t } from "elysia"; +import { swagger } from "@elysiajs/swagger"; import { JSONSchema7 } from "json-schema"; -import { defs } from "@slub/json-schema-utils"; +import { + convertDefsToDefinitions, + defs, + extendSchemaShortcut, + propertyExistsWithinSchema, +} from "@slub/json-schema-utils"; import { getGraphQLWriter, getJsonSchemaReader, makeConverter } from "typeconv"; import { cors } from "@elysiajs/cors"; import { yoga } from "@elysiajs/graphql-yoga"; import { FieldNode, SelectionSetNode } from "graphql"; import { IExecutableSchemaDefinition } from "@graphql-tools/schema"; import { IFieldResolver } from "@graphql-tools/utils"; -import loadedSchema from "@slub/exhibition-schema/schemas/jsonschema/Exhibition.schema.json"; -import { defsToDefinitions } from "./defsToDefinitions"; -import { dataStore } from "./dataStore"; -import { extendSchema } from "./extendSchema"; -import { replaceJSONLD } from "./replaceJSONLD"; +import { primaryFields, schema } from "@slub/exhibition-schema"; +import { filterUndefOrNull, replaceJSONLD } from "@slub/edb-core-utils"; +import qs from "qs"; +import * as process from "process"; +import { PrismaClient } from "@prisma/edb-exhibition-client"; +import config from "@slub/exhibition-sparql-config"; +import { initPrismaStore } from "@slub/prisma-db-impl"; +import { typeIRItoTypeName, typeNameToTypeIRI } from "./dataStore"; -const exhibitionSchema = extendSchema(loadedSchema as JSONSchema7); +console.log(process.env.DATABASE_PROVIDER); +const schemaName = `${schema.title || schema.$id || "unnamed schema"}`; + +const exhibitionSchema = extendSchemaShortcut( + schema as JSONSchema7, + "_type", + "_id", +); +const rootSchema = extendSchemaShortcut(schema as JSONSchema7, "type", "id"); +const prisma = new PrismaClient(); +const dataStore = initPrismaStore(prisma, rootSchema, primaryFields, { + jsonldContext: config.defaultJsonldContext, + defaultPrefix: config.defaultPrefix, + typeIRItoTypeName: typeIRItoTypeName, + typeNameToTypeIRI: typeNameToTypeIRI, +}); +//bun only runs if we call it here: why?? +//find first object that can be counted: +for (const key of Object.keys(prisma)) { + if (prisma[key]?.count) { + const c = await prisma[key].count(); + console.log(c); + break; + } +} const reader = getJsonSchemaReader(); const writer = getGraphQLWriter(); -const convertDefs = (schema: T) => { - if (!schema["$defs"]) return schema; - const { $defs: definitions, ...rest } = defsToDefinitions(schema); - return { - ...rest, - definitions, - } as T; -}; - const converter = makeConverter(reader, writer); const { data: graphqlTypeDefsUnfiltered } = await converter.convert({ - data: JSON.stringify(convertDefs(exhibitionSchema), null, 2), + data: JSON.stringify(convertDefsToDefinitions(exhibitionSchema), null, 2), }); const graphqlTypeDefs = graphqlTypeDefsUnfiltered @@ -44,7 +68,7 @@ const getTypeDefs = (schema: JSONSchema7) => { .map((typeName) => { return ` get${typeName}(id: ID!): ${typeName} - list${typeName}: [${typeName}] + list${typeName}(limit: Int): [${typeName}] `; }) .join("\n"); @@ -70,7 +94,8 @@ const getFieldResolvers = (schema: JSONSchema7) => { [ `list${typeName}`, async (parent, args, context, info) => { - return replaceJSONLD(await dataStore.listDocuments(typeName, 10)); + const { limit = 10 } = args; + return replaceJSONLD(await dataStore.listDocuments(typeName, limit)); }, ], ]; @@ -82,6 +107,31 @@ const getFieldResolvers = (schema: JSONSchema7) => { const additionalTypeDefs = getTypeDefs(exhibitionSchema); const queryResolvers = getFieldResolvers(exhibitionSchema); +const availableTypeNames = Object.keys(defs(exhibitionSchema)); + +const sortingToQuery = (sorting: string[], typeName: string) => { + return filterUndefOrNull( + sorting?.map((s) => { + const sort = s.split(" "); + const propertyPath = sort[0]; + if (propertyPath === "IRI") + return { id: "IRI", desc: sort[1] === "desc" }; + const exists = propertyExistsWithinSchema( + typeName, + propertyPath, + exhibitionSchema, + ); + if (!exists) { + console.warn( + `Property ${propertyPath} does not exist in schema ${typeName}`, + ); + return null; + } + return { id: propertyPath, desc: sort[1] === "desc" }; + }), + ); +}; + const recurseSelectionSet: (selectionSet: SelectionSetNode) => { [p: string]: { [p: string]: any } | null; } = (selectionSet: SelectionSetNode) => { @@ -113,12 +163,228 @@ const graphqlAPI = yoga({ resolvers: gqlSchema.resolvers, } as any); +const typeNameOption = t.Union(availableTypeNames.map((s) => t.Literal(s))); + const app = new Elysia() - .use(cors()) + .use( + cors({ + methods: ["GET", "POST", "DELETE", "PUT"], + }), + ) .use(graphqlAPI) + .onTransform((ctx) => { + const parsed = qs.parse(new URL(ctx.request.url).search.slice(1)); + // @ts-expect-error + ctx.query = parsed; + }) .get("/", () => "Welcome to SLUb EDB") + .get( + "/listDocument/:typeName", + async ({ params: { typeName }, query: { limit } }) => { + return dataStore.listDocuments(typeName, limit); + }, + { + query: t.Object({ + limit: t.Optional(t.Numeric()), + }), + params: t.Object({ + typeName: typeNameOption, + }), + detail: { + summary: "List documents of a certain type", + description: + "List documents of a certain type, specified by typeName, optionally limited by limit", + }, + }, + ) + .get( + "/loadDocument/:typeName", + async ({ params: { typeName }, query: { id } }) => { + return await dataStore.loadDocument(typeName, id); + }, + { + query: t.Object({ + id: t.String(), + }), + params: t.Object({ + typeName: typeNameOption, + }), + response: t.Any(), + }, + ) + .get( + "/existsDocument/:typeName", + async ({ params: { typeName }, query: { id } }) => { + return await dataStore.existsDocument(typeName, id); + }, + { + query: t.Object({ + id: t.String(), + }), + params: t.Object({ + typeName: typeNameOption, + }), + response: t.Boolean(), + }, + ) + .get( + "/findDocuments/:typeName", + async ({ params: { typeName }, query }) => { + const { limit, sorting, ...q } = query; + //const + return dataStore.findDocuments( + typeName, + { + search: q.search, + sorting: sorting ? sortingToQuery(sorting, typeName) : [], + }, + limit, + ); + }, + { + query: t.Object({ + sorting: t.Optional(t.Array(t.String())), + search: t.Optional(t.String()), + limit: t.Optional(t.Numeric()), + }), + params: t.Object({ + typeName: typeNameOption, + }), + }, + ) + .get( + "/classes", + async ({ query: { id } }) => { + if (!dataStore.getClasses) + throw new Error("This data store does not support classes"); + return dataStore.getClasses(id); + }, + { + query: t.Object({ + id: t.String(), + }), + }, + ) + .get( + `/findDocumentsByLabel/:typeName/`, + async ({ params: { typeName }, query }) => { + if (!dataStore.findDocumentsByLabel) { + throw new Error( + "This data store does not support finding documents by label", + ); + } + return dataStore.findDocumentsByLabel(typeName, query.label, query.limit); + }, + { + query: t.Object({ + limit: t.Optional(t.Numeric()), + label: t.String(), + }), + params: t.Object({ + typeName: typeNameOption, + }), + }, + ) + .get( + "/findDocumentsAsFlat/:typeName", + async ({ params: { typeName }, query }) => { + const { limit, ...q } = query; + if (!dataStore.findDocumentsAsFlatResultSet) { + throw new Error("This data store does not support flat result sets"); + } + return dataStore.findDocumentsAsFlatResultSet( + typeName, + { + search: q.search, + sorting: q.sorting ? sortingToQuery(q.sorting, typeName) : [], + }, + limit, + ); + }, + { + query: t.Object({ + sorting: t.Optional(t.Array(t.String())), + search: t.Optional(t.String()), + limit: t.Optional(t.Numeric()), + }), + params: t.Object({ + typeName: typeNameOption, + }), + }, + ) + .get( + `/findDocumentsByAuthorityIRI/:typeName/`, + async ({ params: { typeName }, query }) => { + if (!dataStore.findDocumentsByAuthorityIRI) { + throw new Error( + "This data store does not support finding documents by authority IRI", + ); + } + return dataStore.findDocumentsByAuthorityIRI( + typeName, + query.authorityIRI, + query.repositoryIRI, + query.limit, + ); + }, + { + query: t.Object({ + limit: t.Optional(t.Numeric()), + authorityIRI: t.String(), + repositoryIRI: t.Optional(t.String()), + }), + params: t.Object({ + typeName: typeNameOption, + }), + }, + ) + .put( + "/upsertDocument/:typeName", + async ({ params: { typeName }, body }) => { + const entityIRI = (body as any)["@id"]; + if (!entityIRI) throw new Error("Entity IRI is required"); + return dataStore.upsertDocument(typeName, entityIRI, body); + }, + { + params: t.Object({ + typeName: typeNameOption, + }), + body: t.Object( + { + "@id": t.String(), + }, + { additionalProperties: true }, + ), + }, + ) + //delete an entity + .delete( + "/removeDocument/:typeName", + ({ params: { typeName }, query: { id } }) => { + return Boolean(dataStore.removeDocument(typeName, id)); + }, + { + params: t.Object({ + typeName: typeNameOption, + }), + query: t.Object({ + id: t.String(), + }), + }, + ) + .use( + swagger({ + documentation: { + info: { + title: `EDB API (${schemaName})`, + version: process.env.npm_package_version || "0.0.0.", + description: `API for ${schemaName}`, + }, + }, + }), + ) .listen(3001); console.log( - `🦊 Elysia powered SLUB EDB is running at ${app.server?.hostname}:${app.server?.port}`, + `🦊 Elysia powered EDB (${schemaName}) is running at ${app.server?.hostname}:${app.server?.port}`, ); diff --git a/apps/edb-api/src/replaceJSONLD.ts b/apps/edb-api/src/replaceJSONLD.ts deleted file mode 100644 index 6d7662fd..00000000 --- a/apps/edb-api/src/replaceJSONLD.ts +++ /dev/null @@ -1,22 +0,0 @@ -export const replaceJSONLD = (obj: any, visited = new WeakSet()): any => { - if (obj && typeof obj === "object") { - if (visited.has(obj)) { - return obj; // Avoid infinite recursion by returning already visited objects - } - if (Array.isArray(obj)) { - return obj.map((item) => replaceJSONLD(item, visited)); - } - visited.add(obj); - - return Object.fromEntries( - Object.entries(obj).map(([key, value]: [string, any]) => { - if (key.startsWith("@")) { - return [key.replace("@", "_"), value]; - } else { - return [key, replaceJSONLD(value, visited)]; - } - }), - ); - } - return obj; -}; diff --git a/apps/edb-cli/package.json b/apps/edb-cli/package.json index 813e8f86..337373cb 100644 --- a/apps/edb-cli/package.json +++ b/apps/edb-cli/package.json @@ -28,8 +28,15 @@ "@slub/edb-core-utils": "workspace:*", "@slub/edb-graph-traversal": "workspace:*", "@slub/remote-query-implementations": "workspace:*", + "@slub/prisma-db-impl": "workspace:*", "@slub/sparql-schema": "workspace:*", + "@slub/edb-authorities": "workspace:*", + "@slub/edb-data-mapping": "workspace:*", + "@slub/edb-cli-creator": "workspace:*", + "@slub/edb-file-import": "workspace:*", "@tpluscode/sparql-builder": "^0.3.31", - "cmd-ts": "^0.13.0" + "cmd-ts": "^0.13.0", + "uuid": "^10.0.0", + "csv-parse": "^5.5.6" } } diff --git a/apps/edb-cli/src/auhtorityAccess.ts b/apps/edb-cli/src/auhtorityAccess.ts new file mode 100644 index 00000000..bddf35fd --- /dev/null +++ b/apps/edb-cli/src/auhtorityAccess.ts @@ -0,0 +1,15 @@ +import { findEntityWithinLobidByIRI } from "@slub/edb-authorities"; +import { AuthorityConfiguration } from "@slub/edb-data-mapping"; +import { getEntityFromWikidataByIRI } from "@slub/edb-ui-utils"; + +export const authorityAccess: Record = { + "http://d-nb.info/gnd": { + authorityIRI: "http://d-nb.info/gnd", + getEntityByIRI: findEntityWithinLobidByIRI, + }, + "http://www.wikidata.org": { + authorityIRI: "http://www.wikidata.org", + getEntityByIRI: async (id) => + await getEntityFromWikidataByIRI(id, { rank: "preferred" }), + }, +}; diff --git a/apps/edb-cli/src/csvToModel.ts b/apps/edb-cli/src/csvToModel.ts new file mode 100644 index 00000000..5b0b7cec --- /dev/null +++ b/apps/edb-cli/src/csvToModel.ts @@ -0,0 +1,34 @@ +import { + DeclarativeMatchBasedFlatMappings, + mapFromFlatResource, + StrategyContext, +} from "@slub/edb-data-mapping"; +import { v3 as uuidv3 } from "uuid"; +import { slent } from "@slub/exhibition-sparql-config"; +import { processCSV } from "./mapping"; +import { dataStore } from "./dataStore"; + +export const csvToModel = async ( + file: string, + typeName: string, + matchBasedFlatMappings: DeclarativeMatchBasedFlatMappings, + strategyContext: StrategyContext, + onMappedData: ( + entityIRI: string, + mappedData: any, + originalRecord: string[], + index: number, + ) => Promise, + amount?: number, + offset?: number, +) => + await mapFromFlatResource( + dataStore.typeNameToTypeIRI(typeName), + matchBasedFlatMappings, + strategyContext, + processCSV(file), + (record: string[]) => slent(uuidv3(record.join(), uuidv3.URL)).value, + onMappedData, + amount, + offset, + ); diff --git a/apps/edb-cli/src/dataStore.ts b/apps/edb-cli/src/dataStore.ts index bcb94faa..d695c8d0 100644 --- a/apps/edb-cli/src/dataStore.ts +++ b/apps/edb-cli/src/dataStore.ts @@ -1,32 +1,64 @@ import config from "@slub/exhibition-sparql-config"; -import { oxigraphCrudOptions } from "@slub/remote-query-implementations"; -import { initSPARQLStore } from "@slub/sparql-db-impl"; -import schema from "@slub/exhibition-schema/schemas/jsonschema/Exhibition.schema.json"; +import { + getProviderOrDefault, + getSPARQLFlavour, +} from "@slub/remote-query-implementations"; +import { initSPARQLDataStoreFromConfig } from "@slub/sparql-db-impl"; +import { extendSchemaShortcut } from "@slub/json-schema-utils"; +import { primaryFields, schema } from "@slub/exhibition-schema"; import { JSONSchema7 } from "json-schema"; +import { initPrismaStore } from "@slub/prisma-db-impl"; +//import { PrismaClient } from "@prisma/edb-exhibition-client"; -const { - namespace, - walkerOptions, - defaultPrefix, - defaultQueryBuilderOptions, - sparqlEndpoint, -} = config; -const crudOptions = oxigraphCrudOptions(sparqlEndpoint); export const typeNameToTypeIRI = (typeName: string) => - namespace(typeName).value; + config.namespace(typeName).value; -export const dataStore = initSPARQLStore({ - defaultPrefix, - typeNameToTypeIRI, - queryBuildOptions: defaultQueryBuilderOptions, - walkerOptions: { - maxRecursion: 4, - maxRecursionEachRef: 2, - skipAtLevel: 1, - omitEmptyArrays: true, - omitEmptyObjects: true, - }, - sparqlQueryFunctions: crudOptions, - schema: schema as JSONSchema7, - defaultLimit: 10, -}); +export const typeIRItoTypeName = (iri: string) => { + return iri?.substring(config.BASE_IRI.length, iri.length); +}; +const initPrisma = async () => { + const rootSchema = extendSchemaShortcut(schema as JSONSchema7, "type", "id"); + // @ts-ignore + const PrismaClient = await import("@prisma/edb-exhibition-client").then( + ({ PrismaClient }) => PrismaClient, + ); + const prisma = new PrismaClient(); + //bun only runs if we call it here: why?? + //find first object that can be counted: + for (const key of Object.keys(prisma)) { + if (prisma[key]?.count) { + const c = await prisma[key].count(); + console.log(c); + break; + } + } + return initPrismaStore(prisma, rootSchema, primaryFields, { + jsonldContext: config.defaultJsonldContext, + defaultPrefix: config.defaultPrefix, + typeIRItoTypeName: typeIRItoTypeName, + typeNameToTypeIRI: typeNameToTypeIRI, + }); +}; + +export const provider = getProviderOrDefault(config.sparqlEndpoint); +if (!provider) { + throw new Error("No provider found for the given SPARQL endpoint"); +} +export const crudFunctions = provider(config.sparqlEndpoint); + +export const dataStore = + process.env.DATABASE_PROVIDER === "sparql" + ? initSPARQLDataStoreFromConfig( + config, + crudFunctions, + getSPARQLFlavour(config.sparqlEndpoint), + ) + : await initPrisma(); + +export const importStores = { + oxigraph: initSPARQLDataStoreFromConfig( + config, + crudFunctions, + getSPARQLFlavour(config.sparqlEndpoint), + ), +}; diff --git a/apps/edb-cli/src/filterJSONLD.ts b/apps/edb-cli/src/filterJSONLD.ts deleted file mode 100644 index 1adc1986..00000000 --- a/apps/edb-cli/src/filterJSONLD.ts +++ /dev/null @@ -1,21 +0,0 @@ -export const filterJSONLD = (obj: any, visited = new WeakSet()): any => { - if (obj && typeof obj === "object") { - if (Array.isArray(obj)) { - return obj.map((item) => filterJSONLD(item, visited)); - } - if (visited.has(obj)) { - return obj; // Avoid infinite recursion by returning already visited objects - } - visited.add(obj); - - return Object.fromEntries( - Object.entries(obj) - .filter(([key]: [string, any]) => (key.startsWith("@") ? false : true)) - .map(([key, value]: [string, any]) => [ - key, - filterJSONLD(value, visited), - ]), - ); - } - return obj; -}; diff --git a/apps/edb-cli/src/flatImportHandler.ts b/apps/edb-cli/src/flatImportHandler.ts new file mode 100644 index 00000000..ec6e2e0a --- /dev/null +++ b/apps/edb-cli/src/flatImportHandler.ts @@ -0,0 +1,48 @@ +import { csvToModel } from "./csvToModel"; +import { getDefaultMappingStrategyContext } from "./mappingStrategyContext"; +import { dataStore } from "./dataStore"; +import { availableFlatMappings } from "@slub/exhibition-schema"; +import { FlatImportHandler } from "@slub/edb-cli-creator"; + +export const flatImportHandler: FlatImportHandler = async ({ + file, + mimeType, + mappingDeclaration, + amount, + offset, + dryRun, + debug, +}) => { + const { typeName, mapping } = availableFlatMappings[mappingDeclaration]; + let importCounter = 0; + const mappingStrategyContext = getDefaultMappingStrategyContext(!debug); + await csvToModel( + file, + typeName, + mapping, + // @ts-ignore + mappingStrategyContext, + async ( + entityIRI: string, + mappedData: any, + originalRecord: string[], + index: number, + ) => { + if (dryRun) { + console.log( + `Dry run: would import entity ${importCounter + 1} from row ${index}: ${entityIRI}`, + ); + console.dir(mappedData, { depth: null }); + } else { + await dataStore.upsertDocument(typeName, entityIRI, mappedData); + console.log( + `Imported entity ${importCounter + 1} from row ${index}: ${entityIRI}`, + ); + } + importCounter++; + }, + amount, + offset, + ); + process.exit(0); +}; diff --git a/apps/edb-cli/src/index.ts b/apps/edb-cli/src/index.ts index 8cfef85a..fd93d4d9 100644 --- a/apps/edb-cli/src/index.ts +++ b/apps/edb-cli/src/index.ts @@ -1,101 +1,29 @@ -import { - boolean, - command, - flag, - number, - option, - optional, - positional, - run, - string, - subcommands, -} from "cmd-ts"; -import { filterJSONLD } from "./filterJSONLD"; -import { dataStore } from "./dataStore"; +import { run, subcommands } from "cmd-ts"; +import { dataStore, importStores } from "./dataStore"; +import { flatImportHandler } from "./flatImportHandler"; +import { availableFlatMappings } from "@slub/exhibition-schema"; +import { makeEdbCli } from "@slub/edb-cli-creator"; +import { schema } from "@slub/exhibition-schema"; +import { seedHandler } from "./seedHandler"; +import { mapFromAuthority } from "./mapFromAuthority"; +import { authorityAccess } from "./auhtorityAccess"; -const formatResult = (result: any, pretty?: boolean, noJsonLD?: boolean) => { - const res = noJsonLD ? filterJSONLD(result) : result; - return pretty ? JSON.stringify(res, null, 2) : JSON.stringify(res); -}; +const cli = makeEdbCli( + schema, + dataStore, + importStores, + availableFlatMappings, + flatImportHandler, + seedHandler, + mapFromAuthority, + authorityAccess, +); -const get = command({ - name: "edb-cli get", - args: { - entityIRI: positional({ - type: string, - displayName: "entityIRI", - description: "the IRI of the entity to fetch", - }), - type: option({ - type: optional(string), - description: "The Type of the document", - long: "type", - short: "t", - }), - pretty: flag({ - type: boolean, - description: "Pretty print the output", - long: "pretty", - short: "p", - }), - noJsonld: flag({ - type: boolean, - description: "Filter JSON-LD properties", - long: "no-jsonld", - }), - }, - handler: async ({ entityIRI, type, pretty, noJsonld }) => { - if (!type) { - throw new Error("Loading an entity without type currently not supported"); - } - const item = await dataStore.loadDocument(type, entityIRI); - console.log(formatResult(item, pretty, noJsonld)); - }, -}); - -const list = command({ - name: "edb-cli list", - args: { - type: positional({ - type: string, - displayName: "Type Name", - description: "The Type of the document", - }), - amount: option({ - type: optional(number), - description: "The amount of documents to fetch", - long: "amount", - short: "n", - }), - search: option({ - type: optional(string), - description: "The search string", - long: "search", - short: "s", - }), - pretty: flag({ - type: boolean, - description: "Pretty print the output", - long: "pretty", - short: "p", - }), - noJsonld: flag({ - type: boolean, - description: "Filter JSON-LD properties", - long: "no-jsonld", - }), - }, - handler: ({ type, amount = 1, search, pretty, noJsonld }) => { - dataStore.findDocuments(type, { search }, amount, (item) => { - console.log(formatResult(item, pretty, noJsonld)); - return Promise.resolve(); - }); - }, -}); - -const ownSubcommand = subcommands({ - name: "list", - cmds: { list, get }, -}); - -run(ownSubcommand, process.argv.slice(2)); +run( + subcommands({ + name: "edb-cli", + version: "0.0.1", + cmds: cli, + }), + process.argv.slice(2), +); diff --git a/apps/edb-cli/src/mapFromAuthority.ts b/apps/edb-cli/src/mapFromAuthority.ts new file mode 100644 index 00000000..ee37e9f6 --- /dev/null +++ b/apps/edb-cli/src/mapFromAuthority.ts @@ -0,0 +1,46 @@ +import { MapFromAuthorityHandler } from "@slub/edb-cli-creator"; +import { NormDataMapping } from "@slub/edb-core-types"; +import { mapByConfig } from "@slub/edb-data-mapping"; +import { availableAuthorityMappings } from "@slub/exhibition-schema"; +import { dataStore } from "src/dataStore"; +import { getDefaultMappingStrategyContext } from "./mappingStrategyContext"; + +const getMappingConfig = ( + normDataMapping: Record, + authorityIRI: string, + typeName: string, +) => { + const declarativeMapping = normDataMapping[authorityIRI]; + if (!declarativeMapping) { + throw new Error(`no mapping declaration config for ${authorityIRI}`); + } + const mappingConfig = declarativeMapping.mapping[typeName]; + if (!mappingConfig) { + throw new Error(`no mapping config for ${typeName}`); + } + + return mappingConfig; +}; +export const mapFromAuthority: MapFromAuthorityHandler = async ( + id: string | undefined, + classIRI: string, + entryData: any, + authorityIRI: string, + limit: number = 1, + options, +) => { + const disableLogging = !options?.enableLogging; + const mappingConfig = getMappingConfig( + availableAuthorityMappings, + authorityIRI, + dataStore.typeIRItoTypeName(classIRI), + ); + const dataFromAuthority = await mapByConfig( + entryData.allProps, + {}, + mappingConfig, + // @ts-ignore + getDefaultMappingStrategyContext(disableLogging), + ); + return dataFromAuthority; +}; diff --git a/apps/edb-cli/src/mapping/index.ts b/apps/edb-cli/src/mapping/index.ts new file mode 100644 index 00000000..cfac4ae4 --- /dev/null +++ b/apps/edb-cli/src/mapping/index.ts @@ -0,0 +1 @@ +export * from "./processCSV"; diff --git a/apps/edb-cli/src/mapping/processCSV.ts b/apps/edb-cli/src/mapping/processCSV.ts new file mode 100644 index 00000000..f3f19dbc --- /dev/null +++ b/apps/edb-cli/src/mapping/processCSV.ts @@ -0,0 +1,40 @@ +import { ProcessFlatResourceFn } from "@slub/edb-data-mapping"; +import fs from "fs"; +import path from "path"; +import { parse } from "csv-parse"; + +/** + * returns a function to process a specific CSV file using the ProcessFlatResourceFn interface + * using the csv-parse library + * + * @param file the path to the CSV file + */ +export const processCSV: (file: string) => ProcessFlatResourceFn = (file) => { + const processCSVResource: ProcessFlatResourceFn = async ( + headerCallback: (header: string[]) => Promise, + recordCallback: (record: string[], index: number) => Promise, + amount?: number, + offset?: number, + ) => { + const parser = fs.createReadStream(path.resolve(file)).pipe(parse({})); + let index = 0, + recordCount = 0; + for await (const record of parser) { + if (index === 0) { + await headerCallback(record as string[]); + } else { + if (offset && index < offset) { + index++; + continue; + } + await recordCallback(record as string[], index); + recordCount++; + } + if (amount && recordCount >= amount) { + break; + } + index++; + } + }; + return processCSVResource; +}; diff --git a/apps/edb-cli/src/mappingStrategyContext.ts b/apps/edb-cli/src/mappingStrategyContext.ts new file mode 100644 index 00000000..684717fe --- /dev/null +++ b/apps/edb-cli/src/mappingStrategyContext.ts @@ -0,0 +1,138 @@ +import { + IRIToStringFn, + Prefixes, + PrimaryFieldDeclaration, + QueryBuilderOptions, +} from "@slub/edb-core-types"; +import { + createLogger, + makeCreateDeeperContextFn, + StrategyContext, +} from "@slub/edb-data-mapping"; +import { + findEntityByAuthorityIRI, + searchEntityByLabel, +} from "@slub/sparql-schema"; +import config, { slent } from "@slub/exhibition-sparql-config"; +import { v4 as uuidv4 } from "uuid"; +import { + availableAuthorityMappings, + primaryFields, +} from "@slub/exhibition-schema"; +import { crudFunctions, dataStore } from "./dataStore"; +import { authorityAccess } from "./auhtorityAccess"; + +export const makeMappingStrategyContext: ( + doQuery: (query: string) => Promise, + queryBuilderOptions: QueryBuilderOptions, + createEntityIRI: (typeIRI: string) => string, + typeIRIToTypeName: IRIToStringFn, + primaryFields: PrimaryFieldDeclaration, + disableLogging?: boolean, +) => StrategyContext = ( + doQuery, + queryBuilderOptions, + createEntityIRI, + typeIRItoTypeName, + primaryFields, + disableLogging = false, +) => ({ + getPrimaryIRIBySecondaryIRI: async ( + secondaryIRI: string, + authorityIRI: string, + typeIRI?: string | undefined, + ) => { + // @ts-ignore + const ids = await findEntityByAuthorityIRI( + secondaryIRI, + typeIRI, + doQuery, + 100, + queryBuilderOptions, + ); + if (ids.length > 1) { + console.warn( + `found more than one entity (${ids.length}), will use the first`, + ); + } + return ids[0] || null; + }, + searchEntityByLabel: async ( + label: string, + typeIRI: string, + ): Promise => { + // @ts-ignore + const ids = await searchEntityByLabel(label, typeIRI, doQuery, undefined, { + ...queryBuilderOptions, + typeIRItoTypeName, + primaryFields, + }); + if (ids.length > 1) { + console.warn( + `found more than one entity ( ${ids.length} ), will use the first `, + ); + } + return ids[0] || null; + }, + authorityAccess, + authorityIRI: "http://d-nb.info/gnd", + newIRI: createEntityIRI, + typeIRItoTypeName: typeIRItoTypeName, + primaryFields: primaryFields, + normDataMappings: availableAuthorityMappings, + path: [], + logger: createLogger([], disableLogging), + createDeeperContext: makeCreateDeeperContextFn(disableLogging), +}); + +const { defaultPrefix, defaultQueryBuilderOptions } = config; + +export const createNewIRI = () => slent(uuidv4()).value; +export const getDefaultMappingStrategyContext = (disableLogging?: boolean) => ({ + ...makeMappingStrategyContext( + crudFunctions.selectFetch, + { + prefixes: defaultQueryBuilderOptions.prefixes as Prefixes, + defaultPrefix, + }, + createNewIRI, + dataStore.typeIRItoTypeName, + primaryFields, + disableLogging, + ), + getPrimaryIRIBySecondaryIRI: async ( + secondaryIRI: string, + authorityIRI: string, + typeIRI: string, + ) => { + const typeName = dataStore.typeIRItoTypeName(typeIRI); + if (!dataStore.findDocumentsByAuthorityIRI) { + return Promise.reject("datastore does not support find"); + } + return await dataStore + .findDocumentsByAuthorityIRI(typeName, secondaryIRI, authorityIRI) + .then((res) => res[0] as string); + }, + + searchEntityByLabel: async ( + label: string, + typeIRI: string, + ): Promise => { + const typeName = dataStore.typeIRItoTypeName(typeIRI); + if (!dataStore.findDocumentsByLabel) + return Promise.reject("datastore does not support find"); + const doc = await dataStore + .findDocumentsByLabel(typeName, label) + .then((res) => res[0] as string); + return doc; + }, + onNewDocument: async (document: any) => { + const typeName = dataStore.typeIRItoTypeName(document["@type"]); + await dataStore.upsertDocument(typeName, document["@id"], document); + return { + "@id": document["@id"], + "@type": document["@type"], + }; + }, + logger: createLogger([], !!disableLogging), +}); diff --git a/apps/edb-cli/src/seedHandler.ts b/apps/edb-cli/src/seedHandler.ts new file mode 100644 index 00000000..aeb3ef22 --- /dev/null +++ b/apps/edb-cli/src/seedHandler.ts @@ -0,0 +1,17 @@ +import { SemanticSeedHandler } from "@slub/edb-cli-creator"; +import { processEachDocumentFromFile } from "@slub/edb-file-import"; +import config from "@slub/exhibition-sparql-config"; +import { typeNameToTypeIRI } from "./dataStore"; + +export const seedHandler: SemanticSeedHandler = async ({ + file, + schema, + onDocument, +}) => { + return processEachDocumentFromFile(file, schema, onDocument, { + jsonldContext: config.defaultJsonldContext, + defaultPrefix: config.defaultPrefix, + walkerOptions: config.walkerOptions, + typeNameToTypeIRI: typeNameToTypeIRI, + }); +}; diff --git a/apps/edb-mongo-api/package.json b/apps/edb-mongo-api/package.json deleted file mode 100644 index 21a026e4..00000000 --- a/apps/edb-mongo-api/package.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "name": "@slub/edb-mongo-api", - "description": "Simple API to interact with EDB on MongoDB", - "version": "1.1.0", - "type": "module", - "main": "index.js", - "scripts": { - "start": "tsx src/index.ts", - "start-graphiql": "docker run --name graphiql -p 4000:4000 -e API_URL=http://localhost:3001/graphql npalm/graphiql", - "start:mongo": "docker run --name mongodb -p 27017:27017 -d mongodb/mongodb-community-server:latest", - "dev": "tsx watch src/index.ts", - "start:debug": "node --inspect --loader tsx 'src/index.ts'" - }, - "keywords": [], - "author": "Sebastian Tilsch ", - "license": "MIT", - "devDependencies": { - "@slub/edb-tsconfig": "workspace:*", - "@tsconfig/node18": "^18.2.2", - "bun-types": "^1.0.30", - "graphiql-explorer": "^0.9.0", - "tsx": "^4.7.1", - "typescript": "^5.4.2" - }, - "dependencies": { - "@benzene/http": "^0.4.2", - "@elysiajs/eden": "^1.0.8", - "@elysiajs/cors": "^1.0.2", - "@elysiajs/swagger": "^1.0.3", - "@elysiajs/graphql-yoga": "^1.0.2", - "@graphql-tools/schema": "^10.0.3", - "@rdfjs/data-model": "^2.0.2", - "@rdfjs/namespace": "^2.0.1", - "@slub/exhibition-schema": "workspace:*", - "@slub/edb-core-utils": "workspace:*", - "@slub/edb-graph-traversal": "workspace:*", - "@slub/remote-query-implementations": "workspace:*", - "@slub/sparql-schema": "workspace:*", - "@slub/json-schema-utils": "workspace:*", - "@tpluscode/sparql-builder": "^0.3.31", - "@sinclair/typebox": "^0.32.20", - "cmd-ts": "^0.13.0", - "elysia": "^1.0.10", - "graphql": "^16.8.1", - "graphql-mobius": "^0.1.13", - "graphql-tag": "^2.12.6", - "json-schema": "^0.4.0", - "typeconv": "^2.3.1", - "mongodb": "^6.5.0" - } -} diff --git a/apps/edb-mongo-api/src/config.ts b/apps/edb-mongo-api/src/config.ts deleted file mode 100644 index 0d06e71a..00000000 --- a/apps/edb-mongo-api/src/config.ts +++ /dev/null @@ -1,38 +0,0 @@ -import namespace, { NamespaceBuilder } from "@rdfjs/namespace"; -import { Config } from "@slub/edb-global-types"; - -const BASE_IRI = "http://ontologies.slub-dresden.de/exhibition#"; -export const sladb = namespace(BASE_IRI); -export const slent = namespace(`${BASE_IRI}/entity/`); -export const defaultPrefix = sladb[""].value; - -export default { - BASE_IRI, - API_URL: "http://sdvahndmgtest.slub-dresden.de:8000/graphql", - namespaceBase: "http://ontologies.slub-dresden.de/exhibition#", - namespace: namespace("http://ontologies.slub-dresden.de/exhibition#"), - defaultPrefix: "http://ontologies.slub-dresden.de/exhibition#", - walkerOptions: { - maxRecursion: 8, - maxRecursionEachRef: 8, - skipAtLevel: 10, - omitEmptyArrays: true, - omitEmptyObjects: true, - }, - defaultJsonldContext: { - "@vocab": defaultPrefix, - xs: "http://www.w3.org/2001/XMLSchema#", - image: { - "@type": "xs:anyURI", - }, - }, - defaultQueryBuilderOptions: { - prefixes: { [""]: sladb, slent }, - }, - sparqlEndpoint: { - label: "Ausstellungsdatenbank", - endpoint: "https://ausstellungsdatenbank.kuenste.live/query", - provider: "oxigraph", - active: true, - }, -} as Config; diff --git a/apps/edb-mongo-api/src/connect.ts b/apps/edb-mongo-api/src/connect.ts deleted file mode 100644 index 965bd737..00000000 --- a/apps/edb-mongo-api/src/connect.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { MongoClient } from "mongodb"; - -// Replace the uri string with your connection string. -const uri = "mongodb://localhost:27017/adbSample"; -const client = new MongoClient(uri); -export const database = client.db("adbSample"); - -export const closeConnection = async () => client.close(); diff --git a/apps/edb-mongo-api/src/index.ts b/apps/edb-mongo-api/src/index.ts deleted file mode 100644 index f9421d2c..00000000 --- a/apps/edb-mongo-api/src/index.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { Elysia, t } from "elysia"; -import { cors } from "@elysiajs/cors"; -import { closeConnection, database } from "./connect"; -import { swagger } from "@elysiajs/swagger"; -import { Collection } from "mongodb"; - -const ensureIndex = (collection: Collection) => { - if (!collection.indexExists("@id")) collection.createIndex({ "@id": 1 }); -}; -const postDocument: ( - typeName: string, - entityIRI: string, - document: any, -) => Promise = async ( - typeName: string, - entityIRI: string, - document: any, -) => { - const coll = database.collection(typeName); - ensureIndex(coll); - return coll.findOneAndReplace({ "@id": entityIRI }, document, { - upsert: true, - }); -}; -export const app = new Elysia() - .use(cors()) - .get("/", () => "Welcome to SLUb EDB Mongo API") - .get( - "/document/:typeName/:entityIRI", - async ({ params: { typeName, entityIRI } }) => { - const id = decodeURIComponent(entityIRI), - coll = database.collection(typeName); - return (await coll.findOne({ "@id": id })) || {}; - }, - { - params: t.Object({ - typeName: t.String(), - entityIRI: t.String(), - }), - response: t.Any(), - }, - ) - .post( - "/document", - async ({ body }) => { - const { typeName, entityIRI, data } = body; - return await postDocument(typeName, entityIRI, data); - }, - { - body: t.Object({ - typeName: t.String(), - entityIRI: t.String(), - data: t.Any(), - }), - }, - ) - // @ts-ignore - .use(swagger()) - .listen(3002); - -export type App = typeof app; - -app.onStop(() => { - console.log( - `🦊 Elysia powered SLUB EDB Mongo API is shutting down at ${app.server?.hostname}:${app.server?.port}`, - ); - closeConnection(); -}); -console.log( - `🦊 Elysia powered SLUB EDB Mongo API is running at ${app.server?.hostname}:${app.server?.port}`, -); diff --git a/apps/edb-mongo-api/src/loader.ts b/apps/edb-mongo-api/src/loader.ts deleted file mode 100644 index bb6f055a..00000000 --- a/apps/edb-mongo-api/src/loader.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { oxigraphCrudOptions } from "@slub/remote-query-implementations"; -import { bringDefinitionToTop } from "@slub/json-schema-utils"; -import { JSONSchema7 } from "json-schema"; -import { findEntityByClass, load } from "@slub/sparql-schema"; -import { QueryOptions } from "@slub/edb-core-types"; -import config from "./config"; - -const { - BASE_IRI, - namespace, - walkerOptions: defaultWalkerOptions, - defaultPrefix, - defaultJsonldContext, - defaultQueryBuilderOptions, - sparqlEndpoint, -} = config; - -export const typeNameToTypeIRI = (typeName: string) => - namespace(typeName).value; - -const queryOptions: QueryOptions = { - defaultPrefix, - queryBuildOptions: defaultQueryBuilderOptions, -}; - -const crudOptions = oxigraphCrudOptions(sparqlEndpoint); -const { constructFetch, updateFetch, selectFetch } = crudOptions; - -export const loadEntity = async ( - typeName: string, - typeIRI: string, - entityIRI: string, - schema: JSONSchema7, -) => { - if (!constructFetch) return null; - const mySchema = bringDefinitionToTop(schema, typeName) as JSONSchema7; - const res = await load(entityIRI, typeIRI, mySchema, constructFetch, { - defaultPrefix: BASE_IRI, - queryBuildOptions: defaultQueryBuilderOptions, - walkerOptions: defaultWalkerOptions, - }); - return res.document; -}; -export const findEntities = async ( - typeName: string, - amount: number, - schema: JSONSchema7, - search?: string, -) => { - const typeIRI = typeNameToTypeIRI(typeName); - const items = await findEntityByClass( - search || null, - typeIRI, - selectFetch, - { queryBuildOptions: defaultQueryBuilderOptions, defaultPrefix }, - amount, - ); - return await Promise.all( - items.map(({ value }: { value: string }) => { - return loadEntity(typeName, typeIRI, value, schema); - }), - ); -}; diff --git a/apps/edb-mongo-api/src/test.ts b/apps/edb-mongo-api/src/test.ts deleted file mode 100644 index da45e18f..00000000 --- a/apps/edb-mongo-api/src/test.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { edenFetch } from "@elysiajs/eden"; -import type { App } from "./index"; -import { sladb, slent } from "./config"; - -const SERVER_URL = "http://localhost:3002"; - -const fetch = edenFetch(SERVER_URL); - -const catDogIRI = slent("xyz").value; -const typeName = "Animal"; -const postExample = async () => - ( - await fetch("/document", { - method: "POST", - body: { - typeName, - entityIRI: slent("xyz").value, - data: { - "@id": catDogIRI, - "@type": sladb(typeName).value, - name: "Cat-Dog", - description: "An hybrid animal resembling both a cat and a dog", - birthDate: 19990102, - rating: 3.0, - }, - }, - }) - ).data; - -const URL = `/document/${typeName}/${encodeURIComponent(catDogIRI)}`; -const getExample = async () => (await fetch(URL)).data; - -console.log(SERVER_URL + URL); -console.log(JSON.stringify(await getExample(), null, 2)); diff --git a/apps/edb-mongo-api/tsconfig.json b/apps/edb-mongo-api/tsconfig.json deleted file mode 100644 index f3b072e1..00000000 --- a/apps/edb-mongo-api/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "@slub/edb-tsconfig/node-application.json", - "include": ["./src"], - "compilerOptions": { - "baseUrl": ".", - "esModuleInterop": true, - "allowSyntheticDefaultImports": true - }, - "exclude": ["node_modules", ".build"] -} diff --git a/apps/edb-prisma-cli/package.json b/apps/edb-prisma-cli/package.json index e4fa8c45..8cb756e8 100644 --- a/apps/edb-prisma-cli/package.json +++ b/apps/edb-prisma-cli/package.json @@ -7,9 +7,6 @@ "scripts": { "start": "tsx src/index.ts", "dev": "tsx watch src/index.ts", - "model:format": "prisma format", - "prisma:init": "prisma init --datasource-provider postgresql", - "prisma:migrate": "prisma migrate dev --name init", "start:debug": "node --inspect --loader tsx 'src/index.ts'" }, "keywords": [], @@ -36,7 +33,7 @@ "@tpluscode/sparql-builder": "^0.3.31", "cmd-ts": "^0.13.0", "json-schema": "^0.4.0", - "@prisma/client": "^5.11.0", + "@prisma/client": "^5.17.0", "uuid": "^9.0.1", "lodash": "^4.17.21", "cli-progress": "^3" diff --git a/apps/edb-prisma-cli/src/dataStore.ts b/apps/edb-prisma-cli/src/dataStore.ts index ce2b3568..0e4809f6 100644 --- a/apps/edb-prisma-cli/src/dataStore.ts +++ b/apps/edb-prisma-cli/src/dataStore.ts @@ -1,36 +1,17 @@ import config from "@slub/exhibition-sparql-config"; -import { oxigraphCrudOptions } from "@slub/remote-query-implementations"; -import { initSPARQLStore } from "@slub/sparql-db-impl"; -import schema from "@slub/exhibition-schema/schemas/jsonschema/Exhibition.schema.json"; -import { JSONSchema7 } from "json-schema"; +import { + getProviderOrDefault, + getSPARQLFlavour, +} from "@slub/remote-query-implementations"; +import { initSPARQLDataStoreFromConfig } from "@slub/sparql-db-impl"; -const { - BASE_IRI, - namespace, - walkerOptions, - defaultPrefix, - defaultQueryBuilderOptions, - sparqlEndpoint, -} = config; -const crudOptions = oxigraphCrudOptions(sparqlEndpoint); -export const typeNameToTypeIRI = (typeName: string) => - namespace(typeName).value; -export const typeIRItoTypeName = (iri: string) => { - return iri?.substring(BASE_IRI.length, iri.length); -}; +const worker = getProviderOrDefault(config.sparqlEndpoint); -export const dataStore = initSPARQLStore({ - defaultPrefix, - typeNameToTypeIRI, - queryBuildOptions: defaultQueryBuilderOptions, - walkerOptions: { - maxRecursion: 4, - maxRecursionEachRef: 2, - skipAtLevel: 1, - omitEmptyArrays: true, - omitEmptyObjects: true, - }, - sparqlQueryFunctions: crudOptions, - schema: schema as JSONSchema7, - defaultLimit: 10, -}); +if (!worker) { + throw new Error("No worker found for the given SPARQL endpoint"); +} +export const dataStore = initSPARQLDataStoreFromConfig( + config, + worker(config.sparqlEndpoint), + getSPARQLFlavour(config.sparqlEndpoint), +); diff --git a/apps/edb-prisma-cli/src/extendSchema.ts b/apps/edb-prisma-cli/src/extendSchema.ts index 066d41cb..b726de3c 100644 --- a/apps/edb-prisma-cli/src/extendSchema.ts +++ b/apps/edb-prisma-cli/src/extendSchema.ts @@ -1,61 +1,32 @@ -import namespace from "@rdfjs/namespace"; -import { GenJSONLDSemanticPropertiesFunction } from "@slub/json-schema-utils"; import { JSONSchema7 } from "json-schema"; import { - defs, - getDefintitionKey, - withJSONLDProperties, + GeneratePropertiesFunction, + extendDefinitionsWithProperties, } from "@slub/json-schema-utils"; +const makeTypeAndIDProperties: GeneratePropertiesFunction = ( + _modelName: string, +) => ({ + type: { + type: "string", + }, + id: { + type: "string", + }, +}); -export const sladb = namespace("http://ontologies.slub-dresden.de/exhibition#"); -export const slent = namespace( - "http://ontologies.slub-dresden.de/exhibition/entity#", -); -const makeSemanticProperties: ( - baseIRI: string, - entitytBaseIRI: string, -) => GenJSONLDSemanticPropertiesFunction = - (baseIRI: string, entityBaseIRI: string) => (modelName: string) => ({ - type: { - const: `${baseIRI}${modelName}`, - type: "string", - }, - id: { - title: entityBaseIRI, - type: "string", - }, - }); - -const jsonldSemanticPropertiesFunction = makeSemanticProperties( - sladb[""].value, - slent[""].value, -); const genRequiredProperties = (_modelName: string) => { return ["type", "id"]; }; export const extendSchema = (schema: any): JSONSchema7 => { - const excludeTypes = ["AuthorityEntry"]; - const definitionsWithJSONLDProperties = Object.entries(defs(schema)).reduce< - JSONSchema7["definitions"] - >((acc, [key, value]) => { - return excludeTypes?.includes(key) - ? { ...acc, [key]: value } - : { - ...acc, - [key]: withJSONLDProperties( - key, - value as JSONSchema7, - jsonldSemanticPropertiesFunction, - genRequiredProperties, - ), - }; - }, {}) as JSONSchema7["definitions"]; - const definitionsKey = getDefintitionKey(schema); - return { - ...schema, - [definitionsKey]: { - ...definitionsWithJSONLDProperties, + const excludeType = ["AuthorityEntry"]; + + return extendDefinitionsWithProperties( + schema, + makeTypeAndIDProperties, + genRequiredProperties, + { + excludeType, }, - }; + ); }; diff --git a/apps/edb-prisma-cli/src/import.ts b/apps/edb-prisma-cli/src/import.ts index 2b2c7ed4..8d861ce8 100644 --- a/apps/edb-prisma-cli/src/import.ts +++ b/apps/edb-prisma-cli/src/import.ts @@ -1,6 +1,9 @@ import cliProgress from "cli-progress"; -import { PrismaClient } from "@prisma/client"; +import { PrismaClient } from "@prisma/edb-exhibition-client"; import { AbstractDatastore, CountAndIterable } from "@slub/edb-global-types"; +import { dataStore } from "./dataStore"; + +const { typeNameToTypeIRI } = dataStore; type PropertiesAndConnects = { id?: string; @@ -15,7 +18,7 @@ const getPropertiesAndConnects = async ( importError: Set, prefix: string = "", middleware?: ( - typeName: string, + typeIRI: string, entityIRI: string, document: any, importError: Set, @@ -41,7 +44,7 @@ const getPropertiesAndConnects = async ( ) { if (middleware) { const success = await middleware( - typeNameOrigin, + item["@type"], item["@id"], item, importError, @@ -62,7 +65,7 @@ const getPropertiesAndConnects = async ( ) { if (middleware) { const success = await middleware( - typeNameOrigin, + value["@type"], value["@id"], value, importError, @@ -79,6 +82,7 @@ const getPropertiesAndConnects = async ( prisma, importError, `${key}_`, + middleware, ); properties = { ...properties, @@ -175,11 +179,12 @@ const importData = async ( importError, "", async ( - typeName: string, + typeIRI: string, entityIRI: string, document: any, importError: Set, ) => { + const typeName = importStore.typeIRItoTypeName(typeIRI); try { await importStore .loadDocument(typeName, entityIRI) diff --git a/apps/edb-prisma-cli/src/index.ts b/apps/edb-prisma-cli/src/index.ts index 5aaba6e9..37fc35e5 100644 --- a/apps/edb-prisma-cli/src/index.ts +++ b/apps/edb-prisma-cli/src/index.ts @@ -1,4 +1,4 @@ -import schema from "@slub/exhibition-schema/schemas/jsonschema/Exhibition.schema.json"; +import { primaryFields, schema } from "@slub/exhibition-schema"; import { boolean, command, @@ -17,14 +17,23 @@ import { defs } from "@slub/json-schema-utils"; import { JSONSchema7 } from "json-schema"; import { dataStore as sparqlStore } from "./dataStore"; import { extendSchema } from "./extendSchema"; -import { PrismaClient } from "@prisma/client"; -import { primaryFields } from "./primaryFields"; +import { PrismaClient } from "@prisma/edb-exhibition-client"; import { filterJSONLD } from "@slub/edb-core-utils"; const importStore = sparqlStore; const prisma = new PrismaClient(); + const rootSchema = extendSchema(schema as JSONSchema7); const dataStore = prismaStore(prisma, rootSchema, primaryFields); +//bun only runs if we call it here: why?? +//find first object that can be counted: +for (const key of Object.keys(prisma)) { + if (prisma[key]?.count) { + const c = await prisma[key].count(); + //console.log(c) + break; + } +} const allTypes = Object.keys(defs(schema as JSONSchema7)); const importCommand = command({ @@ -54,6 +63,7 @@ const importCommand = command({ } else { await dataStore.importDocuments(typeName, importStore, limit || 10); } + process.exit(0); }, }); @@ -93,6 +103,7 @@ const get = command({ } const item = await dataStore.loadDocument(type, entityIRI); console.log(formatResult(item, pretty, noJsonld)); + process.exit(0); }, }); @@ -127,12 +138,32 @@ const list = command({ description: "Filter JSON-LD properties", long: "no-jsonld", }), + flat: flag({ + type: boolean, + description: + "get the results as flat SPARQL Select like answer result set", + long: "flat", + }), }, - handler: async ({ type, amount = 1, search, pretty, noJsonld }) => { - await dataStore.findDocuments(type, { search }, amount, (item) => { - console.log(formatResult(item, pretty, noJsonld)); - return Promise.resolve(); - }); + handler: async ({ type, amount = 1, flat, search, pretty, noJsonld }) => { + if (flat) { + if (!dataStore.findDocumentsAsFlatResultSet) { + console.error("not implemented"); + process.exit(-1); + } + const results = await dataStore.findDocumentsAsFlatResultSet( + type, + { search }, + amount, + ); + console.log(formatResult(results, pretty, false)); + } else { + await dataStore.findDocuments(type, { search }, amount, (item) => { + console.log(formatResult(item, pretty, noJsonld)); + return Promise.resolve(); + }); + } + process.exit(0); }, }); diff --git a/apps/edb-prisma-cli/src/primaryFields.ts b/apps/edb-prisma-cli/src/primaryFields.ts deleted file mode 100644 index 3ffb3e82..00000000 --- a/apps/edb-prisma-cli/src/primaryFields.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { PrimaryField, PrimaryFieldExtract } from "@slub/edb-core-types"; -import exhibitionSchema from "@slub/exhibition-schema/schemas/jsonschema/Exhibition.schema.json"; - -export type PrimaryFieldDeclaration = { - //typeof keys of exhibitionSchema.$defs - [typeName in keyof typeof exhibitionSchema.$defs]: PrimaryField; -}; - -export type PrimaryFieldExtractDeclaration = { - //typeof keys of exhibitionSchema.$defs - [typeName in keyof typeof exhibitionSchema.$defs]: PrimaryFieldExtract; -}; - -const defaultMapping: PrimaryField = { - label: "title", - description: "description", -}; - -const defaultMappingWithImg: PrimaryField = { - label: "title", - description: "description", - image: "image", -}; - -export const primaryFields: Partial = { - Exhibition: defaultMappingWithImg, - Tag: defaultMappingWithImg, - Person: { - ...defaultMappingWithImg, - label: "name", - }, - Corporation: { - ...defaultMapping, - label: "name", - }, - ExhibitionExponat: defaultMappingWithImg, - Genre: defaultMappingWithImg, - Place: defaultMappingWithImg, - Location: defaultMappingWithImg, - CorporationRole: defaultMapping, - PersonRole: defaultMapping, - ExhibitionSeries: defaultMapping, - SeriesType: defaultMapping, - EventType: defaultMapping, - Resource: defaultMapping, - Occupation: defaultMapping, - ExhibitionCategory: { - ...defaultMapping, - label: "name", - }, -}; - -export const primaryFieldExtracts: Partial = { - ...primaryFields, - InvolvedPerson: { - label: { - path: "person.name", - }, - description: { - path: "role.title", - }, - image: { - path: "person.image", - }, - }, - InvolvedCorporation: { - label: { - path: "corporation.name", - }, - description: { - path: "role.title", - }, - image: { - path: "corporation.image", - }, - }, -}; diff --git a/apps/edb-prisma-cli/src/prismaStore.ts b/apps/edb-prisma-cli/src/prismaStore.ts index c22befc4..a03940ac 100644 --- a/apps/edb-prisma-cli/src/prismaStore.ts +++ b/apps/edb-prisma-cli/src/prismaStore.ts @@ -1,14 +1,19 @@ -import { PrismaClient } from "@prisma/client"; -import { jsonSchema2PrismaSelect } from "@slub/json-schema-prisma-utils"; +import { + jsonSchema2PrismaFlatSelect, + jsonSchema2PrismaSelect, +} from "@slub/json-schema-prisma-utils"; import { JSONSchema7 } from "json-schema"; import { toJSONLD } from "./toJSONLD"; import { AbstractDatastore } from "@slub/edb-global-types"; -import { PrimaryFieldDeclaration } from "./primaryFields"; import { importAllDocuments, importSingleDocument } from "./import"; -import { typeIRItoTypeName, typeNameToTypeIRI } from "./dataStore"; +import { dataStore } from "./dataStore"; +import { PrimaryFieldDeclaration } from "@slub/edb-core-types"; +import { defs } from "@slub/json-schema-utils"; + +const { typeNameToTypeIRI, typeIRItoTypeName } = dataStore; export const prismaStore: ( - prisma: PrismaClient, + prisma: any, rootSchema: JSONSchema7, primaryFields: Partial, ) => AbstractDatastore = (prisma, rootSchema, primaryFields) => { @@ -36,6 +41,24 @@ export const prismaStore: ( return entries.map((entry: any) => toJSONLD(entry)); }; + const loadManyFlat = async ( + typeName: string, + limit?: number, + innerLimit?: number, + ) => { + const query = jsonSchema2PrismaFlatSelect( + typeName, + rootSchema, + primaryFields, + { takeLimit: innerLimit ?? limit ?? 0 }, + ); + const entries = await prisma[typeName].findMany({ + take: limit, + ...query, + }); + return entries; + }; + const searchMany = async ( typeName: string, searchString: string, @@ -57,7 +80,7 @@ export const prismaStore: ( take: limit, select, }); - return entries.map((entry) => toJSONLD(entry)); + return entries.map((entry: any) => toJSONLD(entry)); }; const dataStore: AbstractDatastore = { typeNameToTypeIRI: typeNameToTypeIRI, @@ -99,6 +122,30 @@ export const prismaStore: ( }, }); }, + getClasses: async (entityIRI) => { + //we will use a rather primitive way to get the classes in future we could create its own IRI<->Class index and use a prisma middleware to keep it up to date + const definitions = defs(rootSchema); + const allTypeNames = Object.keys(definitions); + const classes = []; + for (const typeName of allTypeNames) { + try { + const entry = await prisma[typeName].findUnique({ + where: { + id: entityIRI, + }, + select: { + id: true, + }, + }); + if (entry) { + classes.push(typeNameToTypeIRI(typeName)); + } + } catch (e) { + console.error("Error while trying to get class for", e); + } + } + return classes; + }, upsertDocument: async (typeName: string, document: any) => {}, listDocuments: async (typeName: string, limit: number = 10, cb) => { const entries = await loadMany(typeName, limit); @@ -109,6 +156,9 @@ export const prismaStore: ( } return entries; }, + findDocumentsAsFlatResultSet: async (typeName, query, limit) => { + return await loadManyFlat(typeName, limit, 2); + }, }; return dataStore; diff --git a/apps/edb-surreal-api/package.json b/apps/edb-surreal-api/package.json index 558c091b..92cf8564 100644 --- a/apps/edb-surreal-api/package.json +++ b/apps/edb-surreal-api/package.json @@ -18,6 +18,7 @@ "license": "MIT", "devDependencies": { "@slub/edb-tsconfig": "workspace:*", + "@slub/edb-core-types": "workspace:*", "@tsconfig/node18": "^18.2.2", "bun-types": "^1.0.30", "tsx": "^4.7.1", diff --git a/apps/exhibition-live/.eslintrc.json b/apps/exhibition-live/.eslintrc.json index 1080d9ec..f2fcc7f9 100644 --- a/apps/exhibition-live/.eslintrc.json +++ b/apps/exhibition-live/.eslintrc.json @@ -3,8 +3,18 @@ "ignorePatterns": [ "components/renderer/**/*.tsx" ], + "plugins": ["react-refresh"], "rules": { + "react-refresh/only-export-components": "warn", "react/display-name": "off", "import/no-anonymous-default-export": "off" - } + }, + "overrides": [ + { + "files": ["pages/**"], + "rules": { + "react-refresh/only-export-components": "off" + } + } + ] } diff --git a/apps/exhibition-live/.storybook/blocks/SBMermaid.tsx b/apps/exhibition-live/.storybook/blocks/SBMermaid.tsx new file mode 100644 index 00000000..daee130d --- /dev/null +++ b/apps/exhibition-live/.storybook/blocks/SBMermaid.tsx @@ -0,0 +1,9 @@ +import React from "react"; +import { Mermaid as MdxMermaid } from "mdx-mermaid/Mermaid"; + +export const SBMermaid = ({ chart }: { chart: string }) => { + if (!chart) { + return null; + } + return React.createElement(MdxMermaid, { chart }); +}; diff --git a/apps/exhibition-live/.storybook/main.ts b/apps/exhibition-live/.storybook/main.ts index aba717ea..66135597 100644 --- a/apps/exhibition-live/.storybook/main.ts +++ b/apps/exhibition-live/.storybook/main.ts @@ -2,8 +2,12 @@ import { StorybookConfig } from "@storybook/nextjs"; const config: StorybookConfig = { stories: [ + "../stories/**/*.mdx", + "../stories/**/*.stories.@(js|jsx|ts|tsx)", "../components/**/*.mdx", "../components/**/*.stories.@(js|jsx|ts|tsx)", + "../../../packages/**/*.stories.@(js|jsx|ts|tsx)", + "../../../packages/**/*.mdx", ], addons: [ @@ -15,7 +19,11 @@ const config: StorybookConfig = { framework: { name: "@storybook/nextjs", - options: {}, + options: { + builder: { + useSWC: true, // Enables SWC support + }, + }, }, docs: { autodocs: true, @@ -29,6 +37,15 @@ const config: StorybookConfig = { }, ], }); + config.resolve = { + ...config.resolve, + fallback: { + ...(config.resolve || {}).fallback, + fs: false, + stream: false, + os: false, + }, + }; return config; }, /* diff --git a/apps/exhibition-live/.storybook/preview.js b/apps/exhibition-live/.storybook/preview.js index f8c139f4..96f04e67 100644 --- a/apps/exhibition-live/.storybook/preview.js +++ b/apps/exhibition-live/.storybook/preview.js @@ -1,8 +1,23 @@ -import theme from "../components/theme/berry-theme"; import { CssBaseline, ThemeProvider } from "@mui/material"; -import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { QueryClient, QueryClientProvider } from "@slub/edb-state-hooks"; + +import { BASE_IRI, PUBLIC_BASE_PATH } from "../components/config"; +import { AdbProvider, store } from "@slub/edb-state-hooks"; +import { EditEntityModal } from "../components/form/edit/EditEntityModal"; +import { EntityDetailModal } from "@slub/edb-advanced-components"; +import { Provider } from "react-redux"; +import { AppRouterContext } from "next/dist/shared/lib/app-router-context.shared-runtime"; +import { exhibitionConfig } from "../components/config/exhibitionAppConfig"; +import { SemanticJsonFormNoOps } from "@slub/edb-linked-data-renderer"; +import { SimilarityFinder } from "../components/form/similarity-finder/SimilarityFinder"; +import { ThemeComponent } from "@slub/edb-default-theme"; +import NiceModal from "@ebay/nice-modal-react"; +import "react-json-view-lite/dist/index.css"; export const parameters = { + nextRouter: { + Provider: AppRouterContext.Provider, // next 13 next 13 (using next/navigation) + }, actions: { argTypesRegex: "^on[A-Z].*" }, controls: { matchers: { @@ -12,22 +27,56 @@ export const parameters = { }, }; -const finalTheme = theme({ - isOpen: [], // for active default menu - defaultId: "default", - fontFamily: "'Roboto', sans-serif", - borderRadius: 12, - opened: true, - navType: "light", -}); const queryClient = new QueryClient(); -export const withMuiTheme = (Story) => ( - - - - - - -); + +export const useRouterMock = () => { + return { + push: async (url) => { + console.log("push", url); + }, + replace: async (url) => { + console.log("replace", url); + }, + asPath: "", + pathname: "", + query: {}, + }; +}; + +export const withMuiTheme = (Story) => { + return ( + + + + + + + + + + + + + ); +}; export const decorators = [withMuiTheme]; diff --git a/apps/exhibition-live/components/utils/image/Img.tsx b/apps/exhibition-live/components/basic/Img.tsx similarity index 66% rename from apps/exhibition-live/components/utils/image/Img.tsx rename to apps/exhibition-live/components/basic/Img.tsx index 78cfecea..b10ba1fe 100644 --- a/apps/exhibition-live/components/utils/image/Img.tsx +++ b/apps/exhibition-live/components/basic/Img.tsx @@ -1,10 +1,9 @@ import Image, { ImageProps } from "next/image"; -import { PUBLIC_BASE_PATH } from "../../config"; -import { useEffect } from "react"; +import { PUBLIC_BASE_PATH } from "../config"; export const Img = ({ src, alt, ...rest }: ImageProps) => ( {alt}, @@ -15,7 +15,7 @@ export const Link = ({ skipLocaleHandling, ...rest }: ExtendedLinkProps) => { - const router = useRouter(); + const router = useModifiedRouter(); let href = useMemo(() => { const locale = rest.locale || router.query.locale || ""; diff --git a/apps/exhibition-live/components/basic/index.ts b/apps/exhibition-live/components/basic/index.ts index c254fc21..c8cdeef6 100644 --- a/apps/exhibition-live/components/basic/index.ts +++ b/apps/exhibition-live/components/basic/index.ts @@ -1,2 +1,2 @@ export * from "./Link"; -export * from "./useModifiedRouter"; +export * from "./Img"; diff --git a/apps/exhibition-live/components/basic/useModifiedRouter.ts b/apps/exhibition-live/components/basic/useModifiedRouter.ts deleted file mode 100644 index 27f0177d..00000000 --- a/apps/exhibition-live/components/basic/useModifiedRouter.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Router, useRouter } from "next/router"; -import { useCallback } from "react"; - -export const useModifiedRouter = () => { - const router = useRouter(); - const locale = router.query.locale || ""; - - const push = useCallback( - async (url, as) => { - let skipLocaleHandling = false; - if (url.toString().indexOf("http") === 0) skipLocaleHandling = true; - if (locale && !skipLocaleHandling) { - return await router.push(`/${locale}${url.toString()}`, as); - } - return false; - }, - [locale, router], - ); - return { - ...router, - push, - }; -}; diff --git a/apps/exhibition-live/components/config/LobidMaping.stories.tsx b/apps/exhibition-live/components/config/LobidMaping.stories.tsx deleted file mode 100644 index 3a9d061f..00000000 --- a/apps/exhibition-live/components/config/LobidMaping.stories.tsx +++ /dev/null @@ -1,140 +0,0 @@ -import { makeDefaultMappingStrategyContext } from "../form/SimilarityFinder"; -import LobidSearchTable, { - gndEntryWithMainInfo, -} from "../form/lobid/LobidSearchTable"; -import { - findEntityWithinLobidByIRI, - findEntityWithinLobidWithCertainProperty, -} from "../utils/lobid/findEntityWithinLobid"; -import { useQuery } from "@tanstack/react-query"; -import React, { useEffect, useMemo, useState } from "react"; -import { declarativeMappings } from "./lobidMappings"; -import { mapByConfig } from "../utils/mapping/mapByConfig"; -import { useGlobalCRUDOptions } from "../state/useGlobalCRUDOptions"; -import { JsonView } from "react-json-view-lite"; -import { Grid, List, TextField } from "@mui/material"; -import ClassicResultListItem from "../form/result/ClassicResultListItem"; -import { sladb } from "../form/formConfigs"; - -export default { - title: "forms/mapping/LobidMapping", -}; - -const LobidMappingTester = ({ - gndID, - typeName, -}: { - gndID: string; - typeName: string; -}) => { - const { data: allProps } = useQuery(["lobid", gndID], () => - findEntityWithinLobidByIRI(gndID), - ); - const { crudOptions } = useGlobalCRUDOptions(); - const [mappedData, setMappedData] = useState({}); - - useEffect(() => { - if (!allProps) return; - const mappingConfig = declarativeMappings[typeName]; - if (!mappingConfig) { - console.warn(`no mapping config for ${typeName}`); - return; - } - try { - mapByConfig( - allProps, - {}, - mappingConfig, - makeDefaultMappingStrategyContext( - crudOptions?.selectFetch, - declarativeMappings, - ), - ).then((mappedData_) => { - setMappedData(mappedData_); - }); - } catch (e) {} - return; - }, [allProps, crudOptions?.selectFetch, typeName]); - return ( -
-

Mapping for {gndID}

- - - lvl < 5} /> - - - lvl < 5} - /> - - - lvl < 5} - /> - - - -
- ); -}; -export const LobidMappingDefault = () => { - const gndID = "https://d-nb.info/gnd/1256926108"; - const typeName = "Exhibition"; - return ; -}; - -export const LobidMappingPerson = () => { - const gndID = "https://d-nb.info/gnd/141691824"; - const typeName = "Person"; - return ; -}; - -export const LobidSearchForProperty = () => { - const [propertyName, setPropertyName] = useState( - "hierarchicalSuperiorOfTheConferenceOrEvent", - ); - const [selectedId, setSelectedId] = useState(undefined); - const { data: entries } = useQuery(["lobid", propertyName], async () => { - const res = await findEntityWithinLobidWithCertainProperty( - propertyName, - undefined, - "ConferenceOrEvent", - ); - return res?.member?.map((allProps: any) => gndEntryWithMainInfo(allProps)); - }); - - return ( - <> - setPropertyName(e.target.value)} - /> - {selectedId && ( - - )} - - {// @ts-ignore - entries?.map(({ id, label, avatar, secondary }, idx) => { - return ( - - ); - })} - - - ); -}; diff --git a/apps/exhibition-live/components/config/exhibitionAppConfig.ts b/apps/exhibition-live/components/config/exhibitionAppConfig.ts new file mode 100644 index 00000000..bd16c3e4 --- /dev/null +++ b/apps/exhibition-live/components/config/exhibitionAppConfig.ts @@ -0,0 +1,47 @@ +import { + createNewIRI, + defaultJsonldContext, + defaultPrefix, + defaultQueryBuilderOptions, + sladb, +} from "./formConfigs"; +import { BASE_IRI } from "./paths"; +import { + availableAuthorityMappings, + makeStubSchema, + schema, +} from "@slub/exhibition-schema"; +import { JSONSchema7 } from "json-schema"; +import { makeDefaultUiSchemaForAllDefinitions } from "./makeDefaultUiSchemaForAllDefinitions"; +import { rendererRegistry } from "./rendererRegistry"; +import { materialCells } from "@jsonforms/material-renderers"; +import { primaryFieldsRegistry } from "./primaryFieldsRegistry"; +import { uischemata } from "./uischemata"; + +const someNameToTypeIRI = (name: string) => sladb(name).value; +const someIRIToTypeName = (iri: string) => + iri?.substring(BASE_IRI.length, iri.length); +export const exhibitionConfig = { + queryBuildOptions: defaultQueryBuilderOptions, + typeNameToTypeIRI: someNameToTypeIRI, + propertyNameToIRI: someNameToTypeIRI, + typeIRIToTypeName: someIRIToTypeName, + propertyIRIToPropertyName: someIRIToTypeName, + createEntityIRI: createNewIRI, + jsonLDConfig: { + defaultPrefix: defaultPrefix, + jsonldContext: defaultJsonldContext, + allowUnsafeSourceIRIs: false, + }, + normDataMapping: availableAuthorityMappings, + schema: schema as JSONSchema7, + makeStubSchema: makeStubSchema, + uiSchemaDefaultRegistry: makeDefaultUiSchemaForAllDefinitions( + schema as JSONSchema7, + ), + rendererRegistry: rendererRegistry, + cellRendererRegistry: materialCells, + primaryFieldRendererRegistry: (typeIRI: string) => + primaryFieldsRegistry(typeIRI, someIRIToTypeName), + uischemata: uischemata, +}; diff --git a/apps/exhibition-live/components/config/formConfigs.ts b/apps/exhibition-live/components/config/formConfigs.ts new file mode 100644 index 00000000..356e0951 --- /dev/null +++ b/apps/exhibition-live/components/config/formConfigs.ts @@ -0,0 +1,34 @@ +import namespace from "@rdfjs/namespace"; +import { SparqlBuildOptions } from "@slub/edb-core-types"; +import { v4 as uuidv4 } from "uuid"; +import { typeIRItoTypeName } from "./index"; +import { primaryFieldExtracts, primaryFields } from "@slub/exhibition-schema"; + +export const sladb = namespace("http://ontologies.slub-dresden.de/exhibition#"); +export const slent = namespace( + "http://ontologies.slub-dresden.de/exhibition/entity/", +); +export const defaultPrefix = sladb[""].value; +export const defaultJsonldContext = { + "@vocab": defaultPrefix, + xs: "http://www.w3.org/2001/XMLSchema#", + id: { + "@type": "@id", + }, + image: { + "@type": "xs:anyURI", + }, +}; + +export const defaultQueryBuilderOptions: SparqlBuildOptions = { + prefixes: { [""]: sladb[""].value, slent: slent[""].value }, + propertyToIRI: (property: string) => { + return sladb[property].value; + }, + typeIRItoTypeName: typeIRItoTypeName, + primaryFields: primaryFields, + primaryFieldExtracts: primaryFieldExtracts, + sparqlFlavour: "oxigraph", +}; + +export const createNewIRI = () => slent(uuidv4()).value; diff --git a/apps/exhibition-live/components/config/index.ts b/apps/exhibition-live/components/config/index.ts index 4b2d366b..99dd3864 100644 --- a/apps/exhibition-live/components/config/index.ts +++ b/apps/exhibition-live/components/config/index.ts @@ -1,9 +1,6 @@ -export const BASE_IRI = "http://ontologies.slub-dresden.de/exhibition#"; -export const API_URL = "http://sdvahndmgtest.slub-dresden.de:8000/graphql"; - -export const PUBLIC_BASE_PATH = process.env.NEXT_PUBLIC_BASE_PATH || ""; - -export * from "./lobidMappings"; -export * from "./primaryFields"; +export * from "./paths"; export * from "./permissions"; export * from "./typeIRIToTypeName"; +export * from "./rendererRegistry"; +export * from "./primaryFieldsRegistry"; +export * from "./makeDefaultUiSchemaForAllDefinitions"; diff --git a/apps/exhibition-live/components/config/kulinarikAppConfig.ts b/apps/exhibition-live/components/config/kulinarikAppConfig.ts new file mode 100644 index 00000000..2fbe9a70 --- /dev/null +++ b/apps/exhibition-live/components/config/kulinarikAppConfig.ts @@ -0,0 +1,92 @@ +import { + makeStubSchema, + primaryFields, + primaryFieldExtracts, + schema, +} from "@slub/kulinarik-schema"; +import { JSONSchema7 } from "json-schema"; +import { makeDefaultUiSchemaForAllDefinitions } from "./makeDefaultUiSchemaForAllDefinitions"; +import { rendererRegistry } from "./rendererRegistry"; +import { materialCells } from "@jsonforms/material-renderers"; +import { IRIToStringFn, SparqlBuildOptions } from "@slub/edb-core-types"; +import { JsonFormsRendererRegistryEntry } from "@jsonforms/core"; +import { + primaryTextFieldControlTester, + PrimaryTextFieldRenderer, +} from "../renderer"; +import namespace from "@rdfjs/namespace"; +import { v4 as uuidv4 } from "uuid"; + +const BASE_IRI = "http://ontologies.slub-dresden.de/kulinarik#"; +const sladb = namespace(BASE_IRI); +const slent = namespace("http://ontologies.slub-dresden.de/kulinarik/entity/"); + +export const typeIRItoTypeName = (iri: string) => { + return iri?.substring(BASE_IRI.length, iri.length); +}; + +const defaultPrefix = sladb[""].value; +const defaultJsonldContext = { + "@vocab": defaultPrefix, + xs: "http://www.w3.org/2001/XMLSchema#", + image: { + "@type": "xs:anyURI", + }, +}; + +const defaultQueryBuilderOptions: SparqlBuildOptions = { + prefixes: { [""]: sladb[""].value, slent: slent[""].value }, + propertyToIRI: (property: string) => { + return sladb[property].value; + }, + typeIRItoTypeName: typeIRItoTypeName, + primaryFields: primaryFields, + primaryFieldExtracts: primaryFieldExtracts, + sparqlFlavour: "oxigraph", +}; + +const createNewIRI = () => slent(uuidv4()).value; +const primaryFieldsRegistry: ( + typeIRI: string, + typeIRItoTypeName: IRIToStringFn, +) => JsonFormsRendererRegistryEntry[] = (typeIRI, typeIRIToTypeName) => + primaryFields[typeIRIToTypeName(typeIRI)]?.label + ? [ + { + tester: primaryTextFieldControlTester(typeIRIToTypeName(typeIRI)), + renderer: PrimaryTextFieldRenderer, + }, + ] + : []; +const someNameToTypeIRI = (name: string) => sladb(name).value; +const someIRIToTypeName = (iri: string) => + iri?.substring(BASE_IRI.length, iri.length); +export const kulinarikAppConfig = { + queryBuildOptions: defaultQueryBuilderOptions, + typeNameToTypeIRI: someNameToTypeIRI, + propertyNameToIRI: someNameToTypeIRI, + typeIRIToTypeName: someIRIToTypeName, + propertyIRIToPropertyName: someIRIToTypeName, + createEntityIRI: createNewIRI, + jsonLDConfig: { + defaultPrefix: defaultPrefix, + jsonldContext: defaultJsonldContext, + allowUnsafeSourceIRIs: false, + }, + normDataMapping: { + gnd: { + mapping: [], + typeToTypeMap: {}, + }, + }, + schema: schema as JSONSchema7, + makeStubSchema: makeStubSchema, + uiSchemaDefaultRegistry: makeDefaultUiSchemaForAllDefinitions( + schema as JSONSchema7, + ), + rendererRegistry: rendererRegistry, + cellRendererRegistry: materialCells, + primaryFieldRendererRegistry: (typeIRI: string) => + primaryFieldsRegistry(typeIRI, someIRIToTypeName), + uischemata: undefined, +}; diff --git a/apps/exhibition-live/components/config/lobidMappings.test.ts b/apps/exhibition-live/components/config/lobidMappings.test.ts index 6d815059..2cfe2b71 100644 --- a/apps/exhibition-live/components/config/lobidMappings.test.ts +++ b/apps/exhibition-live/components/config/lobidMappings.test.ts @@ -2,9 +2,13 @@ import { describe, expect, test } from "@jest/globals"; import exampleData from "../../fixtures/lobid/documeta-1257120557.json"; import rendevousData from "../../fixtures/lobid/1256926108.json"; -import { mapByConfig } from "../utils/mapping/mapByConfig"; -import { StrategyContext } from "../utils/mapping/mappingStrategies"; -import { exhibitionDeclarativeMapping } from "./lobidMappings"; +import { typeIRItoTypeName } from "./typeIRIToTypeName"; +import { mapByConfig, StrategyContext } from "@slub/edb-data-mapping"; +import { + declarativeMappings, + exhibitionDeclarativeMapping, + primaryFields, +} from "@slub/exhibition-schema"; let i = 0; @@ -26,6 +30,9 @@ const strategyContext: StrategyContext = { //console.warn("using stub method"); return `http://example.com/${i++}`; }, + primaryFields: primaryFields, + typeIRItoTypeName: typeIRItoTypeName, + declarativeMappings: declarativeMappings, }; describe("apply different mapping strategies", () => { test("can map simple exhibition", () => { diff --git a/apps/exhibition-live/components/form/uischemas.ts b/apps/exhibition-live/components/config/makeDefaultUiSchemaForAllDefinitions.ts similarity index 67% rename from apps/exhibition-live/components/form/uischemas.ts rename to apps/exhibition-live/components/config/makeDefaultUiSchemaForAllDefinitions.ts index f628b749..31f1d606 100644 --- a/apps/exhibition-live/components/form/uischemas.ts +++ b/apps/exhibition-live/components/config/makeDefaultUiSchemaForAllDefinitions.ts @@ -1,6 +1,8 @@ import { JsonFormsUISchemaRegistryEntry } from "@jsonforms/core"; -import { BASE_IRI } from "../config"; +import { BASE_IRI } from "./index"; +import { defs } from "@slub/json-schema-utils"; +import { JSONSchema7 } from "json-schema"; const labels: Record = { Person: "Person", @@ -26,8 +28,18 @@ const additionalOptions: Record = { ExhibitionCategory: { dropdown: true, }, + ResourceType: { + dropdown: true, + }, + SeriesType: { + dropdown: true, + }, }; -const createStubLayout = (defs: string, baseIRI: string, label?: string) => ({ +export const createStubLayout = ( + defs: string, + baseIRI: string, + label?: string, +) => ({ type: "VerticalLayout", elements: [ { @@ -63,29 +75,10 @@ const createUiSchema: ( }, uischema: createStubLayout(key, baseIRI, label), }); -export const uischemas: JsonFormsUISchemaRegistryEntry[] = [ - "Tag", - "Authority", - "SeriesType", - "ExhibitionSeries", - "Person", - "Workplace", - "Location", - "PersonRole", - "CorporationRole", - "Place", - "EventType", - "Corporation", - "ResourceType", - "Resource", - "ExponatsAndPersons", - "ExponatsAndCorporations", - "ExhibitionExponat", - "ExhibitionCategory", - "InvolvedPerson", - "InvolvedCorporation", - "ExhibitionWebLink", - "Genre", - "Exhibition", - "Occupation", -].map((key) => createUiSchema(key, BASE_IRI)); + +export const makeDefaultUiSchemaForAllDefinitions: ( + schema: JSONSchema7, +) => JsonFormsUISchemaRegistryEntry[] = (schema) => + Object.keys(defs(schema as JSONSchema7)).map((key) => + createUiSchema(key, BASE_IRI), + ); diff --git a/apps/exhibition-live/components/config/paths.ts b/apps/exhibition-live/components/config/paths.ts new file mode 100644 index 00000000..bfcfa633 --- /dev/null +++ b/apps/exhibition-live/components/config/paths.ts @@ -0,0 +1,4 @@ +export const BASE_IRI = "http://ontologies.slub-dresden.de/exhibition#"; + +export const PUBLIC_BASE_PATH = + typeof process !== "undefined" ? process.env.NEXT_PUBLIC_BASE_PATH : ""; diff --git a/apps/exhibition-live/components/config/permissions.ts b/apps/exhibition-live/components/config/permissions.ts index 344015c0..0c065847 100644 --- a/apps/exhibition-live/components/config/permissions.ts +++ b/apps/exhibition-live/components/config/permissions.ts @@ -1,9 +1,4 @@ -import exhibitionSchema from "../../public/schema/Exhibition.schema.json"; - -export type Permission = { - view: boolean; - edit: boolean; -}; +import { Permission, PermissionDeclaration } from "@slub/edb-core-types"; export const fullPermission: Permission = { view: true, @@ -22,11 +17,7 @@ export const noPermission: Permission = { export const defaultPermission = viewerPermission; -type ExhibitionPermissionDeclaration = { - [typeName in keyof typeof exhibitionSchema.$defs]: Permission; -}; - -export const editorPermissions: Partial = { +export const editorPermissions: Partial> = { Exhibition: fullPermission, Tag: fullPermission, Person: fullPermission, diff --git a/apps/exhibition-live/components/config/primaryFieldsRegistry.ts b/apps/exhibition-live/components/config/primaryFieldsRegistry.ts new file mode 100644 index 00000000..03c453fb --- /dev/null +++ b/apps/exhibition-live/components/config/primaryFieldsRegistry.ts @@ -0,0 +1,20 @@ +import { JsonFormsRendererRegistryEntry } from "@jsonforms/core"; +import { IRIToStringFn } from "@slub/edb-core-types"; +import { + primaryTextFieldControlTester, + PrimaryTextFieldRenderer, +} from "../renderer"; +import { primaryFields } from "@slub/exhibition-schema"; + +export const primaryFieldsRegistry: ( + typeIRI: string, + typeIRItoTypeName: IRIToStringFn, +) => JsonFormsRendererRegistryEntry[] = (typeIRI, typeIRIToTypeName) => + primaryFields[typeIRIToTypeName(typeIRI)]?.label + ? [ + { + tester: primaryTextFieldControlTester(typeIRIToTypeName(typeIRI)), + renderer: PrimaryTextFieldRenderer, + }, + ] + : []; diff --git a/apps/exhibition-live/components/config/rendererRegistry.ts b/apps/exhibition-live/components/config/rendererRegistry.ts new file mode 100644 index 00000000..ab265c13 --- /dev/null +++ b/apps/exhibition-live/components/config/rendererRegistry.ts @@ -0,0 +1,120 @@ +import { + MaterialBooleanControl, + materialRenderers, +} from "@jsonforms/material-renderers"; +import { + and, + isObjectArray, + isObjectArrayControl, + JsonFormsRendererRegistryEntry, + rankWith, + schemaMatches, + scopeEndsWith, + UISchemaElement, +} from "@jsonforms/core"; +import { JSONSchema7 } from "json-schema"; +import { isEmpty } from "lodash"; +import { MarkdownTextFieldRenderer } from "@slub/edb-markdown-renderer"; +import { + materialCustomAnyOfControlTester, + MaterialCustomAnyOfRenderer, +} from "@slub/edb-layout-renderer"; +import { + adbSpecialDateControlTester, + AdbSpecialDateRenderer, + AutoIdentifierRenderer, + ImageRenderer, + materialBooleanControlTester, + TypeOfRenderer, +} from "@slub/edb-basic-renderer"; +import { + InlineCondensedSemanticFormsRenderer, + InlineDropdownRenderer, + materialArrayChipsLayoutTester, + MaterialArrayOfLinkedItemChipsRenderer, + MaterialArrayOfLinkedItemRenderer, + materialLinkedObjectControlTester, + MaterialLinkedObjectRenderer, +} from "@slub/edb-linked-data-renderer"; + +export const rendererRegistry: JsonFormsRendererRegistryEntry[] = [ + ...materialRenderers, + { + tester: materialCustomAnyOfControlTester, + renderer: MaterialCustomAnyOfRenderer, + }, + { + tester: rankWith(10, scopeEndsWith("image")), + renderer: ImageRenderer, + }, + { + tester: rankWith(10, scopeEndsWith("@id")), + renderer: AutoIdentifierRenderer, + }, + { + tester: rankWith(10, scopeEndsWith("@type")), + renderer: TypeOfRenderer, + }, + { + tester: rankWith( + 5, + and( + isObjectArray, + schemaMatches((schema) => { + if ( + !( + schema.type === "array" && + typeof schema.items === "object" && + (schema.items as JSONSchema7).properties + ) + ) { + return Boolean((schema.items as JSONSchema7).$ref); + } + const props = (schema.items as JSONSchema7).properties; + return Boolean(props["@id"] && props["@type"]); + }), + ), + ), + renderer: MaterialArrayOfLinkedItemRenderer, + }, + { + tester: materialArrayChipsLayoutTester, + renderer: MaterialArrayOfLinkedItemChipsRenderer, + }, + { + tester: rankWith(14, (uischema: UISchemaElement, schema, ctx): boolean => { + if (isEmpty(uischema) || isObjectArrayControl(uischema, schema, ctx)) { + return false; + } + const options = uischema.options; + return !isEmpty(options) && options["inline"]; + }), + renderer: InlineCondensedSemanticFormsRenderer, + }, + { + tester: rankWith(15, (uischema: UISchemaElement, schema, ctx): boolean => { + if (isEmpty(uischema) || isObjectArrayControl(uischema, schema, ctx)) { + return false; + } + const options = uischema.options; + return !isEmpty(options) && options["dropdown"] === true; + }), + renderer: InlineDropdownRenderer, + }, + { + tester: materialLinkedObjectControlTester, + renderer: MaterialLinkedObjectRenderer, + }, + { + tester: adbSpecialDateControlTester, + renderer: AdbSpecialDateRenderer, + }, + { + tester: materialBooleanControlTester, + renderer: MaterialBooleanControl, + }, + { + tester: rankWith(10, scopeEndsWith("description")), + renderer: MarkdownTextFieldRenderer, + }, +]; diff --git a/apps/exhibition-live/components/config/spreadSheetMapping_Hamburg.ts b/apps/exhibition-live/components/config/spreadSheetMapping_Hamburg.ts index 0092b69c..6ae65290 100644 --- a/apps/exhibition-live/components/config/spreadSheetMapping_Hamburg.ts +++ b/apps/exhibition-live/components/config/spreadSheetMapping_Hamburg.ts @@ -1,6 +1,6 @@ -import { DeclarativeFlatMappings } from "../utils/mapping/mappingStrategies"; -import { sladb } from "../form/formConfigs"; +import { sladb } from "./formConfigs"; import { OwnColumnDesc } from "../google/types"; +import { DeclarativeFlatMappings } from "@slub/edb-data-mapping"; export const indexFromLetter = ( letter: string, diff --git a/apps/exhibition-live/components/config/spreadSheetMappings.ts b/apps/exhibition-live/components/config/spreadSheetMappings.ts index 2f76badf..e31cf8c7 100644 --- a/apps/exhibition-live/components/config/spreadSheetMappings.ts +++ b/apps/exhibition-live/components/config/spreadSheetMappings.ts @@ -3,9 +3,11 @@ import { spreadSheetMappings_NewYork, } from "./spreadSheetMappings_NewYork"; import { spreadSheetMapping_Hamburg } from "./spreadSheetMapping_Hamburg"; -import { DeclarativeMatchBasedFlatMappings } from "../utils/mapping/mapMatchBasedByConfig"; import { OwnColumnDesc } from "../google/types"; -import { DeclarativeFlatMappings } from "../utils/mapping/mappingStrategies"; +import { + DeclarativeFlatMappings, + DeclarativeMatchBasedFlatMappings, +} from "@slub/edb-data-mapping"; export type ConcreteSpreadSheetMapping = { raw?: DeclarativeMatchBasedFlatMappings; diff --git a/apps/exhibition-live/components/config/spreadSheetMappings_NewYork.ts b/apps/exhibition-live/components/config/spreadSheetMappings_NewYork.ts index 054b2413..b02d9a7e 100644 --- a/apps/exhibition-live/components/config/spreadSheetMappings_NewYork.ts +++ b/apps/exhibition-live/components/config/spreadSheetMappings_NewYork.ts @@ -1,13 +1,12 @@ -import { DeclarativeFlatMappings } from "../utils/mapping/mappingStrategies"; -import { sladb } from "../form/formConfigs"; +import { sladb } from "./formConfigs"; import { OwnColumnDesc } from "../google/types"; -import { gndBaseIRI } from "../utils/gnd/prefixes"; +import { filterUndefOrNull } from "@slub/edb-core-utils"; +import { gndBaseIRI } from "@slub/edb-authorities"; import { + DeclarativeFlatMappings, DeclarativeMatchBasedFlatMappings, - indexFromTitle, matchBased2DeclarativeFlatMapping, -} from "../utils/mapping/mapMatchBasedByConfig"; -import { filterUndefOrNull } from "@slub/edb-core-utils"; +} from "@slub/edb-data-mapping"; /* B:Name Kiste diff --git a/apps/exhibition-live/components/config/tableConfig.tsx b/apps/exhibition-live/components/config/tableConfig.tsx index 8ebdf8ea..5765c318 100644 --- a/apps/exhibition-live/components/config/tableConfig.tsx +++ b/apps/exhibition-live/components/config/tableConfig.tsx @@ -1,17 +1,7 @@ -import { VisibilityState } from "@tanstack/table-core"; -import { ColumnDefMatcher, mkAccessor } from "../content/list/listHelper"; import { MRT_ColumnDef } from "material-react-table"; -import { numeric2JSDate } from "@slub/edb-core-utils"; import { TFunction } from "i18next"; -import { specialDate2LocalDate } from "../utils/specialDate2LocalDate"; -export type ListConfigType = { - columnVisibility: VisibilityState; - matcher: ColumnDefMatcher; -}; -export type TableConfigRegistry = { - default: Partial; - [typeName: string]: Partial; -}; +import { specialDate2LocalDate } from "@slub/edb-ui-utils"; +import { mkAccessor, TableConfigRegistry } from "@slub/edb-table-components"; const p = (path: string[]) => path.join("_"); const dateColDef: ( key: string, @@ -21,11 +11,17 @@ const dateColDef: ( const columnDef: MRT_ColumnDef = { header: t(p([...path, key])), id: p([...path, key, "single"]), - accessorFn: mkAccessor(`${p([...path, key, "single"])}.value`, "", (v) => - typeof v === "string" || (typeof v === "number" && String(v).length === 8) - ? specialDate2LocalDate(Number(v), "de") - : String(v), - ), + accessorFn: mkAccessor(`${p([...path, key, "single"])}.value`, "", (v) => { + try { + return typeof v === "string" || + (typeof v === "number" && String(v).length === 8) + ? specialDate2LocalDate(Number(v), "de") + : String(v); + } catch (error) { + console.error("Error processing date:", error); + return String(v); + } + }), filterVariant: "date", filterFn: "betweenInclusive", sortingFn: "datetime", @@ -47,11 +43,13 @@ export const tableConfig: TableConfigRegistry = { columnVisibility: { IRI: false, externalId_single: false, + idAuthority_IRI: false, }, }, Exhibition: { columnVisibility: { IRI: false, + idAuthority_IRI: false, externalId_single: false, subtitle_single: false, originalTitle_single: false, @@ -73,6 +71,7 @@ export const tableConfig: TableConfigRegistry = { involvedCorporations_label_group: false, exponats_label_group: false, resources_label_group: false, + placesUnknown_single: false, }, matcher: (key, schemaDef, typeName, t, path) => { if (key === "dateValue") { diff --git a/apps/exhibition-live/components/config/typeIRIToTypeName.ts b/apps/exhibition-live/components/config/typeIRIToTypeName.ts index e0572e14..af78a17e 100644 --- a/apps/exhibition-live/components/config/typeIRIToTypeName.ts +++ b/apps/exhibition-live/components/config/typeIRIToTypeName.ts @@ -1,4 +1,4 @@ -import { BASE_IRI } from "./index"; +import { BASE_IRI } from "./paths"; export const typeIRItoTypeName = (iri: string) => { return iri?.substring(BASE_IRI.length, iri.length); diff --git a/apps/exhibition-live/components/form/uischema/Corporation.uischema.json b/apps/exhibition-live/components/config/uischema/Corporation.uischema.json similarity index 100% rename from apps/exhibition-live/components/form/uischema/Corporation.uischema.json rename to apps/exhibition-live/components/config/uischema/Corporation.uischema.json diff --git a/apps/exhibition-live/components/form/uischema/CorporationRole.uischema.json b/apps/exhibition-live/components/config/uischema/CorporationRole.uischema.json similarity index 100% rename from apps/exhibition-live/components/form/uischema/CorporationRole.uischema.json rename to apps/exhibition-live/components/config/uischema/CorporationRole.uischema.json diff --git a/apps/exhibition-live/components/form/uischema/EventType.uischema.json b/apps/exhibition-live/components/config/uischema/EventType.uischema.json similarity index 75% rename from apps/exhibition-live/components/form/uischema/EventType.uischema.json rename to apps/exhibition-live/components/config/uischema/EventType.uischema.json index a911266c..a0ac0be6 100644 --- a/apps/exhibition-live/components/form/uischema/EventType.uischema.json +++ b/apps/exhibition-live/components/config/uischema/EventType.uischema.json @@ -13,11 +13,6 @@ "type": "Control", "scope": "#/properties/description", "label": "Beschreibung" - }, - { - "type": "Control", - "scope": "#/properties/tags", - "label": "Schlagworte" } ] } diff --git a/apps/exhibition-live/components/config/uischema/Exhibition.uischema.json b/apps/exhibition-live/components/config/uischema/Exhibition.uischema.json new file mode 100644 index 00000000..c63580e8 --- /dev/null +++ b/apps/exhibition-live/components/config/uischema/Exhibition.uischema.json @@ -0,0 +1,384 @@ +{ + "type": "Categorization", + "elements": [ + { + "type": "Category", + "label": "Allgemeine Daten der Ausstellung", + "elements": [ + { + "type": "HorizontalLayout", + "elements": [ + { + "type": "Control", + "label": "Titel der Ausstellung", + "scope": "#/properties/title", + "options": { + "focus": true + } + }, + { + "type": "Control", + "label": "Untertitel", + "scope": "#/properties/subtitle" + }, + { + "type": "Control", + "label": "Originaltitel", + "scope": "#/properties/originalTitle" + } + ] + }, + { + "type": "Control", + "label": "Kurzbeschreibung", + "scope": "#/properties/description", + "options": { + "multi": true + } + }, + { + "type": "HorizontalLayout", + "elements": [ + { + "type": "Control", + "label": "Ausstellungsart", + "scope": "#/properties/exhibitionType" + }, + { + "type": "Control", + "label": "Kategorie", + "scope": "#/properties/exhibitionCategory" + } + ] + }, + { + "type": "Control", + "label": "Genre", + "scope": "#/properties/exhibitionGenre", + "options": { + "chips": true + } + }, + { + "type": "HorizontalLayout", + "elements": [ + { + "type": "Control", + "label": "Ausstellungsserie", + "scope": "#/properties/exhibitionSeries" + }, + { + "type": "Control", + "label": "übergeordnete Ausstellung", + "scope": "#/properties/parent" + } + ] + }, + { + "type": "Control", + "label": "Schlagworte", + "scope": "#/properties/tags", + "options": { + "chips": true + } + }, + { + "type": "Control", + "label": "Bild", + "scope": "#/properties/image" + }, + { + "type": "HorizontalLayout", + "elements": [ + { + "type": "Control", + "scope": "#/properties/@id" + }, + { + "type": "Control", + "scope": "#/properties/@type" + } + ] + } + ] + }, + { + "type": "Category", + "label": "Verortung", + "elements": [ + { + "type": "Control", + "label": "Ausstellungsstätten (Institutionen und Räume)", + "scope": "#/properties/places", + "rule": { + "effect": "DISABLE", + "condition": { + "scope": "#/properties/placesUnknown", + "schema": { + "const": true + } + } + }, + "options": { + "detail": "GENERATED" + } + }, + { + "type": "Control", + "label": "Ausstellungsorte (Städte und Länder)", + "scope": "#/properties/locations", + "options": { + "detail": "GENERATED" + } + }, + { + "type": "Control", + "label": "Ausstellungsstätte unbekannt", + "scope": "#/properties/placesUnknown" + } + ] + }, + { + "type": "Category", + "label": "Zeitlicher Rahmen", + "elements": [ + { + "type": "VerticalLayout", + "elements": [ + { + "type": "Group", + "label": "Ausstellungszeitraum", + "elements": [ + { + "type": "HorizontalLayout", + "elements": [ + { + "type": "Group", + "label": "Beginn", + "elements": [ + { + "type": "Control", + "scope": "#/properties/startDate/properties/dateModifier", + "options": { + "trim": true + } + }, + { + "type": "Control", + "label": "", + "scope": "#/properties/startDate/properties/dateValue" + } + ] + }, + { + "type": "Group", + "label": "Ende", + "elements": [ + { + "type": "Control", + "scope": "#/properties/endDate/properties/dateModifier", + "options": { + "trim": true + } + }, + { + "type": "Control", + "label": "", + "scope": "#/properties/endDate/properties/dateValue" + } + ] + } + ] + } + ] + }, + { + "type": "Group", + "label": "Weitere Zeitangaben", + "elements": [ + { + "type": "HorizontalLayout", + "elements": [ + { + "type": "Control", + "scope": "#/properties/vernissage", + "label": "Vernissage" + }, + { + "type": "Control", + "scope": "#/properties/midissage", + "label": "Midissage" + }, + { + "type": "Control", + "scope": "#/properties/finissage", + "label": "Finissage" + } + ] + } + ] + } + ] + } + ] + }, + { + "type": "Category", + "label": "Personen und Institutionen", + "elements": [ + { + "type": "Group", + "label": "Beteiligte Personen", + "elements": [ + { + "type": "Control", + "label": "Kurator:innen", + "scope": "#/properties/curators", + "options": { + "labelAsHeadline": true + } + }, + { + "type": "Control", + "label": "Weitere beteiligte Personen", + "scope": "#/properties/involvedPersons", + "options": { + "imagePath": "person.image", + "elementLabelTemplate": "{{=it.person?.name || ''}} ({{=it.role?.title || ''}})", + "elementDetailItemPath": "person", + "detail": "GENERATED", + "isReifiedStatement": true, + "autoFocusOnValid": true + } + } + ] + }, + { + "type": "Group", + "label": "Beteiligte Körperschaften", + "elements": [ + { + "type": "Control", + "label": "Veranstalter", + "scope": "#/properties/organizers", + "options": { + "labelAsHeadline": true + } + }, + { + "type": "Control", + "label": "Weitere beteiligte Körperschaften", + "scope": "#/properties/involvedCorporations", + "options": { + "elementImagePath": "corporation.image", + "elementLabelTemplate": "{{=it.corporation?.name || ''}} ({{=it.role?.title || ''}})", + "elementDetailItemPath": "corporation", + "detail": "GENERATED", + "isReifiedStatement": true, + "autoFocusOnValid": true + } + } + ] + } + ] + }, + { + "type": "Category", + "label": "Exponate", + "elements": [ + { + "type": "Control", + "label": "ausgestellte Künstler:innen", + "scope": "#/properties/exposedArtists", + "options": { + "labelAsHeadline": true, + "orderBy": "name" + } + }, + { + "type": "Control", + "label": "Ausgestellte Werke", + "scope": "#/properties/exponats", + "options": { + "labelAsHeadline": true + } + } + ] + }, + { + "type": "Category", + "label": "Quellen", + "elements": [ + { + "type": "Group", + "label": "Quellen zur Ausstellung", + "elements": [ + { + "type": "Control", + "label": "Ausstellungskataloge", + "scope": "#/properties/catalogs", + "options": { + "additionalKnowledgeSources": [ + "k10plus" + ], + "elementLabelProp": "title", + "detail": "GENERATED" + } + }, + { + "type": "Control", + "label": "weitere Quellen", + "scope": "#/properties/resources", + "options": { + "additionalKnowledgeSources": [ + "k10plus" + ], + "elementLabelProp": "title", + "detail": "GENERATED" + } + } + ] + }, + { + "type": "Group", + "label": "Virtuelle Ausstellung", + "elements": [ + { + "type": "Control", + "label": "Link zur virtuellen Ausstellung", + "scope": "#/properties/exhibitionweblink" + } + ] + } + ] + }, + { + "type": "Category", + "label": "Daten zur Erfassung", + "elements": [ + { + "type": "HorizontalLayout", + "elements": [ + { + "type": "Control", + "label": "Veröffentlicht", + "scope": "#/properties/published" + } + ] + }, + { + "type": "Control", + "label": "Erfassungshinweise", + "scope": "#/properties/editorNote", + "options": { + "multi": true + } + } + ] + } + ], + "options": { + "variant": "stepper", + "showNavButtons": true + } +} \ No newline at end of file diff --git a/apps/exhibition-live/components/form/uischema/ExhibitionExponat.uischema.json b/apps/exhibition-live/components/config/uischema/ExhibitionExponat.uischema.json similarity index 100% rename from apps/exhibition-live/components/form/uischema/ExhibitionExponat.uischema.json rename to apps/exhibition-live/components/config/uischema/ExhibitionExponat.uischema.json diff --git a/apps/exhibition-live/components/form/uischema/ExhibitionSeries.uischema.json b/apps/exhibition-live/components/config/uischema/ExhibitionSeries.uischema.json similarity index 100% rename from apps/exhibition-live/components/form/uischema/ExhibitionSeries.uischema.json rename to apps/exhibition-live/components/config/uischema/ExhibitionSeries.uischema.json diff --git a/apps/exhibition-live/components/form/uischema/ExponatsAndCorporations.uischema.json b/apps/exhibition-live/components/config/uischema/ExponatsAndCorporations.uischema.json similarity index 100% rename from apps/exhibition-live/components/form/uischema/ExponatsAndCorporations.uischema.json rename to apps/exhibition-live/components/config/uischema/ExponatsAndCorporations.uischema.json diff --git a/apps/exhibition-live/components/form/uischema/ExponatsAndPersons.uischema.json b/apps/exhibition-live/components/config/uischema/ExponatsAndPersons.uischema.json similarity index 100% rename from apps/exhibition-live/components/form/uischema/ExponatsAndPersons.uischema.json rename to apps/exhibition-live/components/config/uischema/ExponatsAndPersons.uischema.json diff --git a/apps/exhibition-live/components/form/uischema/Genre.uischema.json b/apps/exhibition-live/components/config/uischema/Genre.uischema.json similarity index 100% rename from apps/exhibition-live/components/form/uischema/Genre.uischema.json rename to apps/exhibition-live/components/config/uischema/Genre.uischema.json diff --git a/apps/exhibition-live/components/form/uischema/InvolvedCorporation.uischema.json b/apps/exhibition-live/components/config/uischema/InvolvedCorporation.uischema.json similarity index 100% rename from apps/exhibition-live/components/form/uischema/InvolvedCorporation.uischema.json rename to apps/exhibition-live/components/config/uischema/InvolvedCorporation.uischema.json diff --git a/apps/exhibition-live/components/config/uischema/InvolvedPerson.uischema.json b/apps/exhibition-live/components/config/uischema/InvolvedPerson.uischema.json new file mode 100644 index 00000000..6349f10b --- /dev/null +++ b/apps/exhibition-live/components/config/uischema/InvolvedPerson.uischema.json @@ -0,0 +1,20 @@ +{ + "type": "VerticalLayout", + "elements": [ + { + "type": "HorizontalLayout", + "elements": [ + { + "type": "Control", + "label": "Person", + "scope": "#/properties/person" + }, + { + "type": "Control", + "label": "Rolle in der Ausstellung", + "scope": "#/properties/role" + } + ] + } + ] +} diff --git a/apps/exhibition-live/components/form/uischema/Location.uischema.json b/apps/exhibition-live/components/config/uischema/Location.uischema.json similarity index 100% rename from apps/exhibition-live/components/form/uischema/Location.uischema.json rename to apps/exhibition-live/components/config/uischema/Location.uischema.json diff --git a/apps/exhibition-live/components/form/uischema/Occupation.uischema.json b/apps/exhibition-live/components/config/uischema/Occupation.uischema.json similarity index 100% rename from apps/exhibition-live/components/form/uischema/Occupation.uischema.json rename to apps/exhibition-live/components/config/uischema/Occupation.uischema.json diff --git a/apps/exhibition-live/components/form/uischema/Person.uischema.json b/apps/exhibition-live/components/config/uischema/Person.uischema.json similarity index 100% rename from apps/exhibition-live/components/form/uischema/Person.uischema.json rename to apps/exhibition-live/components/config/uischema/Person.uischema.json diff --git a/apps/exhibition-live/components/form/uischema/PersonRole.uischema.json b/apps/exhibition-live/components/config/uischema/PersonRole.uischema.json similarity index 100% rename from apps/exhibition-live/components/form/uischema/PersonRole.uischema.json rename to apps/exhibition-live/components/config/uischema/PersonRole.uischema.json diff --git a/apps/exhibition-live/components/form/uischema/Place.uischema.json b/apps/exhibition-live/components/config/uischema/Place.uischema.json similarity index 100% rename from apps/exhibition-live/components/form/uischema/Place.uischema.json rename to apps/exhibition-live/components/config/uischema/Place.uischema.json diff --git a/apps/exhibition-live/components/config/uischema/Resource.uischema.json b/apps/exhibition-live/components/config/uischema/Resource.uischema.json new file mode 100644 index 00000000..3eb62c3b --- /dev/null +++ b/apps/exhibition-live/components/config/uischema/Resource.uischema.json @@ -0,0 +1,50 @@ +{ + "type": "VerticalLayout", + "elements": [ + { + "type": "Control", + "scope": "#/properties/title", + "label": "Bezeichnung", + "options": { + "focus": true + } + }, + { + "type": "Control", + "scope": "#/properties/description", + "label": "Beschreibung", + "options": { + "multi": true + } + }, + { + "type": "Control", + "scope": "#/properties/ressourceType" + }, + { + "type": "HorizontalLayout", + "elements": [ + { + "type": "Control", + "scope": "#/properties/ppn" + }, + { + "type": "Control", + "scope": "#/properties/doi" + }, + { + "type": "Control", + "scope": "#/properties/url" + } + ] + }, + { + "type": "Control", + "scope": "#/properties/signature" + }, + { + "type": "Control", + "scope": "#/properties/image" + } + ] +} diff --git a/apps/exhibition-live/components/config/uischema/ResourceType.uischema.json b/apps/exhibition-live/components/config/uischema/ResourceType.uischema.json new file mode 100644 index 00000000..a0ac0be6 --- /dev/null +++ b/apps/exhibition-live/components/config/uischema/ResourceType.uischema.json @@ -0,0 +1,18 @@ +{ + "type": "VerticalLayout", + "elements": [ + { + "type": "Control", + "scope": "#/properties/title", + "label": "Bezeichnung", + "options": { + "focus": true + } + }, + { + "type": "Control", + "scope": "#/properties/description", + "label": "Beschreibung" + } + ] +} diff --git a/apps/exhibition-live/components/form/uischema/SeriesType.uischema.json b/apps/exhibition-live/components/config/uischema/SeriesType.uischema.json similarity index 100% rename from apps/exhibition-live/components/form/uischema/SeriesType.uischema.json rename to apps/exhibition-live/components/config/uischema/SeriesType.uischema.json diff --git a/apps/exhibition-live/components/form/uischema/Tag.uischema.json b/apps/exhibition-live/components/config/uischema/Tag.uischema.json similarity index 100% rename from apps/exhibition-live/components/form/uischema/Tag.uischema.json rename to apps/exhibition-live/components/config/uischema/Tag.uischema.json diff --git a/apps/exhibition-live/components/form/uischema/Workplace.uischema.json b/apps/exhibition-live/components/config/uischema/Workplace.uischema.json similarity index 100% rename from apps/exhibition-live/components/form/uischema/Workplace.uischema.json rename to apps/exhibition-live/components/config/uischema/Workplace.uischema.json diff --git a/apps/exhibition-live/components/form/uischemaForType.ts b/apps/exhibition-live/components/config/uischemata.ts similarity index 59% rename from apps/exhibition-live/components/form/uischemaForType.ts rename to apps/exhibition-live/components/config/uischemata.ts index 204a2b2b..681ffa72 100644 --- a/apps/exhibition-live/components/form/uischemaForType.ts +++ b/apps/exhibition-live/components/config/uischemata.ts @@ -1,27 +1,24 @@ -import { UISchemaElement } from "@jsonforms/core"; -import { useQuery } from "@tanstack/react-query"; -import { useMemo } from "react"; - -import { BASE_IRI } from "../config"; import ExhibitionUISchema from "./uischema/Exhibition.uischema.json"; import ExhibitionExponatUISchema from "./uischema/ExhibitionExponat.uischema.json"; -import ExhibtionSeriesUISchema from "./uischema/ExhibitionSeries.uischema.json"; import InvolvedPersonUISchema from "./uischema/InvolvedPerson.uischema.json"; +import InvolvedCoporationUISchema from "./uischema/InvolvedCorporation.uischema.json"; import LocationUISchema from "./uischema/Location.uischema.json"; import PersonUISchema from "./uischema/Person.uischema.json"; import PlaceUISchema from "./uischema/Place.uischema.json"; import TagUISchema from "./uischema/Tag.uischema.json"; import SeriesTypeUISchema from "./uischema/SeriesType.uischema.json"; import WorkplaceUISchema from "./uischema/Workplace.uischema.json"; +import ExhibitionSeriesUISchema from "./uischema/ExhibitionSeries.uischema.json"; import PersonRoleUISchema from "./uischema/PersonRole.uischema.json"; import CorporationRoleUISchema from "./uischema/CorporationRole.uischema.json"; import EventTypeUISchema from "./uischema/EventType.uischema.json"; import CorporationUISchema from "./uischema/Corporation.uischema.json"; -import InvolvedCoporationUISchema from "./uischema/InvolvedCorporation.uischema.json"; import ExponatsAndPersonsUISchema from "./uischema/ExponatsAndPersons.uischema.json"; import ExponatsAndCorporationsUISchema from "./uischema/ExponatsAndCorporations.uischema.json"; import GenreUISchema from "./uischema/Genre.uischema.json"; import OccupationUISchema from "./uischema/Occupation.uischema.json"; +import ResourceUISchema from "./uischema/Resource.uischema.json"; +import ResourceTypeUISchema from "./uischema/ResourceType.uischema.json"; export const uischemata = { Exhibition: ExhibitionUISchema, @@ -31,10 +28,10 @@ export const uischemata = { Location: LocationUISchema, Person: PersonUISchema, Place: PlaceUISchema, - Tag: TagUISchema, + //Tag: TagUISchema, SeriesType: SeriesTypeUISchema, Workplace: WorkplaceUISchema, - ExhibitionSeries: ExhibtionSeriesUISchema, + ExhibitionSeries: ExhibitionSeriesUISchema, PersonRole: PersonRoleUISchema, CorporationRole: CorporationRoleUISchema, EventType: EventTypeUISchema, @@ -43,38 +40,6 @@ export const uischemata = { ExponatsAndCorporations: ExponatsAndCorporationsUISchema, Genre: GenreUISchema, Occupation: OccupationUISchema, -}; -export const useUISchemaForType = ( - typeIRI: string, - enableLoadFromExternal?: boolean, -) => { - const typeName = useMemo( - () => typeIRI.substring(BASE_IRI.length, typeIRI.length), - [typeIRI], - ); - const uischemaFixed = uischemata[typeName] as UISchemaElement | undefined; - const { data: uiSchemaFromServer } = useQuery( - ["uischema", typeIRI], - async () => { - const url = `./uischema/${typeName}.uischema.json`; - const exists = await fetch(url, { method: "HEAD" }).then((res) => res.ok); - if (exists) { - return await fetch(url) - .then(async (res) => await res.json()) - .catch(() => null); - } - return null; - }, - { - enabled: Boolean(enableLoadFromExternal), - retry: false, - refetchOnWindowFocus: false, - retryOnMount: false, - onError: (err) => {}, - }, - ); - return useMemo( - () => uiSchemaFromServer || uischemaFixed || null, - [uiSchemaFromServer, uischemaFixed], - ); + Resource: ResourceUISchema, + ResourceType: ResourceTypeUISchema, }; diff --git a/apps/exhibition-live/components/content/ContentMainPreview.tsx b/apps/exhibition-live/components/content/ContentMainPreview.tsx deleted file mode 100644 index dd391a5f..00000000 --- a/apps/exhibition-live/components/content/ContentMainPreview.tsx +++ /dev/null @@ -1,219 +0,0 @@ -import dayjs from "dayjs"; -import { Link } from "../basic/Link"; -import React, { FunctionComponent } from "react"; - -interface OwnProps { - exhibition: any; - classIRI: string; -} - -type Props = OwnProps; - -const format = (date?: string) => { - return date ? dayjs(date.substring(1)).format("LL") : ""; -}; - -const Person = ({ person }: { person: any }) => { - return ( -
- - {person.name || ""} {format(person.birth_date)}{" "} - {person.death_date ? `- ${format(person.death_date)}` : ""} - -
- ); -}; - -const ContentMain: FunctionComponent = ({ exhibition }: Props) => { - if (!exhibition) return null; - - return ( - <> -
-
- -

Ausstellung

- -
-
-
-
-
-
-
-
- Kategorie -
-
- - {exhibition?.type || "Kunstausstellung"} - -
-
- Titel -
-
- {exhibition?.title || ""} - - {format(exhibition?.start_date?.date)} -{" "} - {format(exhibition?.end_date?.date)}{" "} - -
-
- Ort -
-
- - {exhibition?.place2} - - →{" "} - - {exhibition?.place1} - - →{" "} - - Sachsen - - →{" "} - - Deutschland - - →{" "} - - Europa - -
-
- Kunstausstellung -
-
- Beteiligte Körperschaften -
-
-
- Kurator -
- {!Array.isArray(exhibition.curator) - ? null - : exhibition.curator.map((person: any) => ( - - ))} - -
- Beteiligte Künstlerinnen und Künstler -
- {!Array.isArray(exhibition.artist) - ? null - : exhibition.artist.map((person: any) => ( - - ))} - -
- Programm -
-
- Quellen -
-
- - Neue Zeitschrift für Musik (NZfM) - - (1872, S. 59f.) -
-
- - Programmzettel - -
-
- - Stadtbibliothek Leipzig - - - {" "} - ( - - https://digital.slub-dresden.de/id507696093 - - ) - - - Voransicht externes Digitalisat{" "} - (795) - - - - - - - Seite 1 von 53 Seiten - - - - → - - - - - -
-
- Projekte -
-
- - Internationalisierung der Symphonik - -
-
-
-
-
-
- - ); -}; - -export default ContentMain; diff --git a/apps/exhibition-live/components/content/charts/chartConfig.ts b/apps/exhibition-live/components/content/charts/chartConfig.ts deleted file mode 100644 index 17950dfa..00000000 --- a/apps/exhibition-live/components/content/charts/chartConfig.ts +++ /dev/null @@ -1 +0,0 @@ -export const ROUNDED_CORNERS = 10; diff --git a/apps/exhibition-live/components/content/drawer/index.ts b/apps/exhibition-live/components/content/drawer/index.ts deleted file mode 100644 index c1a63e88..00000000 --- a/apps/exhibition-live/components/content/drawer/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./ResizableDrawer"; diff --git a/apps/exhibition-live/components/content/list/listHelper.tsx b/apps/exhibition-live/components/content/list/listHelper.tsx deleted file mode 100644 index 218dfcec..00000000 --- a/apps/exhibition-live/components/content/list/listHelper.tsx +++ /dev/null @@ -1,483 +0,0 @@ -import get from "lodash/get"; -import { JSONSchema7, JSONSchema7Definition } from "json-schema"; -import { MRT_ColumnDef, MRT_TableInstance } from "material-react-table"; -import { OverflowContainer } from "../../lists"; -import { isJSONSchema, isPrimitive } from "@slub/json-schema-utils"; -import { Avatar, Box, Checkbox, Grid, Link, Typography } from "@mui/material"; -import isNil from "lodash/isNil"; -import maxBy from "lodash/maxBy"; -import { filterUndefOrNull, parseMarkdownLinks } from "@slub/edb-core-utils"; -import { OverflowChip } from "../../lists/OverflowChip"; -import * as React from "react"; -import { TFunction } from "i18next"; -import { MouseEvent, useCallback, useMemo } from "react"; -import NiceModal from "@ebay/nice-modal-react"; -import { EntityDetailModal } from "../../form/show"; -import { primaryFields } from "../../config"; -import { PrimaryField } from "@slub/edb-core-types"; -import { applyToEachField } from "../../utils/mapping/simpleFieldExtractor"; -import { FieldExtractDeclaration } from "../../utils/types"; -import { - and, - formatIs, - isArrayObjectControl, - isBooleanControl, - isControl, - isOneOfControl, - isStringControl, - JsonSchema, - RankedTester, - rankWith, - Tester, - TesterContext, -} from "@jsonforms/core"; - -const p = (path: string[]) => path.join("_"); -export const mkAccessor = - (path: string, defaultValue?: string | any, fn?: (v: any) => any) => - (row: any) => { - const raw = get(row, path, defaultValue || ""); - return fn ? fn(raw) : raw; - }; -type PathKeyMap = { - [key: string]: { - path: string; - defaultValue?: any; - }; -}; -export const urlSuffix = (uri: string) => { - return uri.substring( - (uri.includes("#") ? uri.lastIndexOf("#") : uri.lastIndexOf("/")) + 1 ?? 0, - uri.length, - ); -}; -export const mkMultiAccessor = (pathKeysMap: PathKeyMap) => (row: any) => { - return Object.fromEntries( - Object.entries(pathKeysMap).map(([key, { path, defaultValue }]) => [ - key, - get(row, path, defaultValue || ""), - ]), - ); -}; - -const extractSingleFieldIfString = ( - entry: any | null, - fieldExtractDeclaration: FieldExtractDeclaration, -): string | null => { - try { - if (typeof fieldExtractDeclaration !== "string") { - return null; - } - const value = entry[`${fieldExtractDeclaration}_single`]?.value; - if (typeof value !== "string") { - return null; - } else { - return value; - } - } catch (e) { - return null; - } -}; - -type PrimaryColumnContentProps = { - entityIRI: string; - typeName: string; - children: React.ReactNode; - data: any; - density?: "comfortable" | "compact" | "spacious"; -}; -export const PrimaryColumnContent = ({ - entityIRI, - typeName, - children, - data, - density, -}: PrimaryColumnContentProps) => { - const primaryContent = useMemo(() => { - const fieldDecl = primaryFields[typeName] as PrimaryField | undefined; - if (data && fieldDecl) - return applyToEachField(data, fieldDecl, extractSingleFieldIfString); - return { - label: null, - description: null, - image: null, - }; - }, [data, typeName]); - const showDetailModal = useCallback( - (e: MouseEvent) => { - e.preventDefault(); - NiceModal.show(EntityDetailModal, { entityIRI, data: {} }); - }, - [entityIRI], - ); - - return ( - - - {primaryContent.image && ( - - )} - {/* using renderedCellValue instead of cell.getValue() preserves filter match highlighting */} - {children} - - - ); -}; -type ComputeColumnDefFunction = ( - typeName: string, - key: string, - schemaDef: JSONSchema7Definition, - t: TFunction, - path?: string[], -) => MRT_ColumnDef; -export interface MuiTableColumnDefinitionRegistryEntry { - tester: RankedTester; - columnDef: ComputeColumnDefFunction; -} - -/** - * generates Column Definition stub with header, id and accessorFn for a single value column - * - * each part will look like `path_to_key_single` - * translation needs to be provided in the form of `path_to_key` using the t-function - * - * @param path path to the key (empty array for root) - * @param key last part of the path - * @param t translation function - */ -const singleValueColumnStub: ( - path: string[], - key: string, - t: TFunction, - label?: string, -) => Pick, "header" | "id" | "accessorFn"> = ( - path, - key, - t, - label, -) => ({ - header: label || t(p([...path, key])), - id: p([...path, key, "single"]), - accessorFn: mkAccessor(`${p([...path, key, "single"])}.value`, ""), -}); - -const isPrimitiveControl: Tester = (_, schema) => - typeof schema.type === "string" && isPrimitive(schema.type); - -const isObjectWithRefControl: Tester = (uischema, schema) => - schema.$ref && isControl(uischema); - -const titleOf = (schema: JSONSchema7Definition) => - (schema as JSONSchema7)?.title; - -const cellConfigRegistry: MuiTableColumnDefinitionRegistryEntry[] = [ - { - tester: rankWith(1, isPrimitiveControl), - columnDef: (typeName, key, schemaDef, t, path) => ({ - ...singleValueColumnStub(path, key, t, titleOf(schemaDef)), - Cell: ({ cell, renderedCellValue, row, table }) => - primaryFields[typeName]?.label === key ? ( - - {renderedCellValue} - - ) : ( - - {renderedCellValue} - - ), - }), - }, - { - tester: rankWith(2, and(isControl, formatIs("uri"))), - columnDef: (typeName, key, schemaDef, t, path) => ({ - ...singleValueColumnStub(path, key, t, titleOf(schemaDef)), - maxSize: 400, - Cell: ({ cell }) => ( - - - {decodeURIComponent(urlSuffix(String(cell.getValue()) ?? ""))} - - - ), - }), - }, - { - tester: rankWith(4, and(isOneOfControl, isStringControl)), - columnDef: (typeName, key, schemaDef, t, path) => { - const def = schemaDef as JSONSchema7; - return { - ...singleValueColumnStub(path, key, t, titleOf(schemaDef)), - maxSize: 400, - filterFn: "equals", - filterSelectOptions: def.oneOf.map((e: JSONSchema7) => ({ - label: e.title || t(`key_${e.const}`), - value: e.const, - })), - filterVariant: "select", - Cell: ({ cell, row, table }) => { - let v: any = cell.getValue(); - if (typeof v === "string" && v.length > 0) { - const oneOfElement = def.oneOf?.find( - (e: JSONSchema7) => e.const === v, - ) as JSONSchema7; - v = oneOfElement?.title || t(`key_${v}`); - } - return ( - - {v} - - ); - }, - }; - }, - }, - { - tester: rankWith(3, isBooleanControl), - columnDef: (typeName, key, schemaDef, t, path) => ({ - ...singleValueColumnStub(path, key, t, titleOf(schemaDef)), - maxSize: 200, - size: 150, - filterVariant: "checkbox", - Cell: ({ cell, row, table }) => { - const v = cell.getValue(); - return ( - <> - - - ); - }, - }), - }, - { - tester: rankWith(2, isArrayObjectControl), - columnDef: (typeName, key, schemaDef, t, path) => { - const id = p([...path, key, "label_group"]); - return { - header: titleOf(schemaDef) || t(p([...path, key])), - id, - maxSize: 500, - accessorFn: mkAccessor( - `${p([...path, key, "label_group"])}.value`, - "", - (v) => - parseMarkdownLinks(v) - .map(({ label }) => label) - .join(", "), - ), - filterFn: "contains", - Cell: ({ renderedCellValue, table, row }) => { - const getValue = mkMultiAccessor({ - group: { - path: `${p([...path, key, "label_group"])}.value`, - defaultValue: "", - }, - count: { - path: `${p([...path, key, "count"])}.value`, - defaultValue: 0, - }, - }); - const { group, count } = getValue(row.original); - const table_ = table as MRT_TableInstance; - return ( - count > 0 && ( - - - {table.getState().columnFilters.find((cf) => cf.id === id) ? ( - {renderedCellValue} - ) : ( - ({count}) - )} - - {!isNil(count) && - count > 0 && - parseMarkdownLinks(group).map(({ label, url }, index) => { - return ( - - - - - - ); - })} - - ) - ); - }, - }; - }, - }, - { - tester: rankWith(2, isObjectWithRefControl), - columnDef: (typeName, key, schemaDef, t, path) => { - const id = p([...path, key, "entity"]); - const labelPath = p([...path, key, "label"]); - const descriptionPath = p([...path, key, "description"]); - const iriPath = p([...path, key, "IRI"]); - return { - header: titleOf(schemaDef) || t(p([...path, key])), - id, - maxSize: 500, - filterVariant: "select", - accessorFn: mkAccessor(`${labelPath}.value`, ""), - Cell: ({ renderedCellValue, table, row }) => { - const description = row.original[descriptionPath]?.value; - const label = row.original[labelPath]?.value; - const iri = row.original[iriPath]?.value; - return ( - iri && - label?.length > 0 && ( - - ) - ); - }, - }; - }, - }, -]; - -export const defaultColumnDefinitionStub: ( - typeName: string, - key: string, - schemaDef: JSONSchema7Definition, - rootSchema: JSONSchema7, - t: TFunction, - path?: string[], -) => MRT_ColumnDef = ( - typeName, - key, - schemaDef, - rootSchema, - t, - path = [], -) => { - const testerContext: TesterContext = { - rootSchema: rootSchema as JsonSchema, - config: {}, - }; - const uiSchema = { - type: "Control", - scope: `#/properties/${key}`, - }; - - const columnDef = maxBy(cellConfigRegistry, (entry) => { - const tested = entry.tester( - uiSchema, - schemaDef as JsonSchema, - testerContext, - ); - return tested; - }); - const rank = columnDef.tester( - uiSchema, - schemaDef as JsonSchema, - testerContext, - ); - //console.log({columnDef}) - return rank > 0 - ? columnDef.columnDef(typeName, key, schemaDef, t, path) - : null; -}; - -export type ColumnDefMatcher = ( - key: string, - schemaDef: JSONSchema7Definition, - typeName: string, - t: TFunction, - path?: string[], -) => MRT_ColumnDef | null; -export const computeColumns: ( - schema: JSONSchema7, - typeName: string, - t: TFunction, - matcher?: ColumnDefMatcher, - path?: string[], -) => MRT_ColumnDef[] = (schema, typeName, t, matcher, path = []) => - (!schema?.properties - ? [] - : [ - { - id: p([...path, "IRI"]), - header: p([...path, "IRI"]), - accessorKey: `${p([...path, "entity"])}.value`, - Cell: ({ cell }) => ( - - {urlSuffix(cell.getValue() ?? "")} - - ), - }, - ...filterUndefOrNull( - Object.entries(schema.properties).map( - ([key, propertyDefinition], index): MRT_ColumnDef => { - const columnDefinition = matcher - ? matcher(key, propertyDefinition, typeName, t, path) - : null; - return ( - columnDefinition || - defaultColumnDefinitionStub( - typeName, - key, - propertyDefinition, - schema, - t, - path, - ) - ); - }, - ), - ), - ...Object.entries(schema.properties || {}) - .filter( - ([, value]) => - typeof value === "object" && - value.type === "object" && - !value.$ref, - ) - .map(([key, value]) => - isJSONSchema(value) - ? computeColumns(value, typeName, t, matcher, [...path, key]) - : [], - ) - .flat(), - ]) as any as MRT_ColumnDef[]; diff --git a/apps/exhibition-live/components/content/main/Dashboard.tsx b/apps/exhibition-live/components/content/main/Dashboard.tsx index eeec6bf0..23ea299d 100644 --- a/apps/exhibition-live/components/content/main/Dashboard.tsx +++ b/apps/exhibition-live/components/content/main/Dashboard.tsx @@ -9,19 +9,17 @@ import { } from "@mui/material"; import Grid2 from "@mui/material/Unstable_Grid2"; import { TrendingDown, TrendingUp } from "@mui/icons-material"; -import { useQuery } from "@tanstack/react-query"; -import { useGlobalCRUDOptions } from "../../state/useGlobalCRUDOptions"; +import { useQuery } from "@slub/edb-state-hooks"; +import { useAdbContext, useGlobalCRUDOptions } from "@slub/edb-state-hooks"; import { SELECT } from "@tpluscode/sparql-builder"; -import { primaryFields, typeIRItoTypeName } from "../../config"; -import { sladb } from "../../form/formConfigs"; -import BarReChart from "../charts/BarReChart"; import { orderBy } from "lodash"; import { useMemo } from "react"; import { SearchBar } from "./Search"; import { ParentSize } from "@visx/responsive"; -import { fixSparqlOrder } from "../../utils/discover"; import df from "@rdfjs/data-model"; import { useTranslation } from "next-i18next"; +import { fixSparqlOrder } from "@slub/sparql-schema"; +import { BarReChart } from "@slub/edb-charts"; export const HeaderTitle = styled(Typography)(({ theme }) => ({ fontFamily: "'Play', sans-serif", @@ -97,9 +95,20 @@ export const OwnCard = ({ ); -const relevantTypes = Object.keys(primaryFields).map((key) => sladb(key).value); - export const Dashboard = (props) => { + const { + queryBuildOptions: { primaryFields }, + typeIRIToTypeName, + typeNameToTypeIRI, + jsonLDConfig: { defaultPrefix }, + propertyNameToIRI, + } = useAdbContext(); + + const relevantTypes = useMemo( + () => Object.keys(primaryFields).map((key) => propertyNameToIRI(key)), + [propertyNameToIRI, primaryFields], + ); + const { t } = useTranslation(); const { crudOptions } = useGlobalCRUDOptions(); const { selectFetch } = crudOptions || {}; @@ -126,17 +135,15 @@ export const Dashboard = (props) => { () => orderBy( typeCountData?.map((item) => ({ - title: t(typeIRItoTypeName(item.type?.value)), + title: t(typeIRIToTypeName(item.type?.value)), score: parseInt(item.count?.value) || 0, })), ["score"], ["desc"], ), - [typeCountData, t], + [typeCountData, t, typeIRIToTypeName], ); - const items = useMemo(() => {}, []); - return ( void; - drawerHeight: number; -}; - -const TimelineViewPart = ({ - data, - timelineOptions, - selectedTimelineItems, - onSelect, -}: { - data: TimelineItem[]; - timelineOptions?: TimelineOptions; - selectedTimelineItems?: string[]; - onSelect?: (items: string[]) => void; -}) => { - return ( - - ); -}; -type TimelineViewProps = {}; -export const TimelineView = ({ - data, - typeIRI, - selectedEntityIRI, - onEntitySelected, - drawerHeight, -}: FlexibleViewDrawerProps & TimelineViewProps) => { - const typeName = useMemo(() => typeIRItoTypeName(typeIRI), [typeIRI]); - const timelineOptions = useMemo( - () => ({ - height: drawerHeight - 50, - multiselect: true, - }), - [drawerHeight], - ); - const timeLineItems = useMemo(() => { - if (typeName !== "Exhibition") return []; - //console.log({table: table.}) - return filterUndefOrNull( - data.map((entity) => { - if (!entity.fromDateDisplay_single?.value) return null; - const startDate = dateValueToDate(entity.fromDateDisplay_single.value); - if (!startDate) return null; - const endDate = - entity.toDateDisplay_single?.value && - entity.toDateDisplay_single.value !== - entity.fromDateDisplay_single.value - ? dateValueToDate(entity.toDateDisplay_single.value) - : undefined; - return { - id: entity.entity?.value, - content: entity.title_single?.value, - start: startDate, - ...(endDate ? { end: endDate } : {}), - }; - }), - ); - }, [data, typeName]); - - return ( - onEntitySelected(items[0]) : undefined - } - /> - ); -}; - -export const DefaultView = ({ - data, - typeIRI, - selectedEntityIRI, - onEntitySelected, -}: FlexibleViewDrawerProps) => { - return ( - - - - ); -}; - -enum ViewType { - Timeline = "timeline", - Table = "table", - Default = "default", -} - -type SemanticListView = { - type: ViewType; - label: string; - icon: React.ReactElement; - component: React.ComponentType; -}; - -const views: SemanticListView[] = [ - { - type: ViewType.Timeline, - label: "Timeline", - icon: , - component: TimelineView, - }, - { - type: ViewType.Default, - label: "Default", - icon: , - component: DefaultView, - }, -]; - -export const FlexibleViewDrawer = ({ - data, - typeIRI, - selectedEntityIRI, - onEntitySelected, -}: FlexibleViewDrawerProps) => { - const typeName = useMemo(() => typeIRItoTypeName(typeIRI), [typeIRI]); - const [selectedView, setSelectedView] = useState(1); - const { setDrawerHeight, drawerHeight } = useDrawerDimensions(); - const handleViewChange = useCallback( - (_e: any, id: number) => { - //if(! event.target.id in ViewType) return; - if (drawerHeight < 100) setDrawerHeight(500); - setSelectedView(id); - }, - [setSelectedView, setDrawerHeight, drawerHeight], - ); - const CurrentSemanticListView = useMemo( - () => views[selectedView]?.component, - [selectedView], - ); - - const [debouncedHeight, setDebouncedHeight] = useState(drawerHeight); - const setDrawerHeightDebounced = useDebounce(setDebouncedHeight, 500); - useEffect(() => { - setDrawerHeightDebounced(drawerHeight); - }, [drawerHeight, setDrawerHeightDebounced]); - - return ( - - - {views.map((viewDesc, index) => ( - - ))} - - {CurrentSemanticListView && ( - - )} - - ); -}; diff --git a/apps/exhibition-live/components/content/main/Search.tsx b/apps/exhibition-live/components/content/main/Search.tsx index aaf53b4e..758a9682 100644 --- a/apps/exhibition-live/components/content/main/Search.tsx +++ b/apps/exhibition-live/components/content/main/Search.tsx @@ -5,33 +5,26 @@ import IconButton from "@mui/material/IconButton"; import SearchIcon from "@mui/icons-material/Search"; import { ParentSize } from "@visx/responsive"; import { useCallback, useMemo, useState } from "react"; -import { useQuery } from "@tanstack/react-query"; -import { useGlobalCRUDOptions } from "../../state/useGlobalCRUDOptions"; +import { useQuery } from "@slub/edb-state-hooks"; +import { useAdbContext, useGlobalCRUDOptions } from "@slub/edb-state-hooks"; import { SELECT } from "@tpluscode/sparql-builder"; -import { primaryFields, typeIRItoTypeName } from "../../config"; -import { defaultPrefix } from "../../form/formConfigs"; import df from "@rdfjs/data-model"; import { isString, orderBy, uniq } from "lodash"; -import { fixSparqlOrder } from "../../utils/discover"; import { Box, Chip, Grid, Skeleton, Tab, Tabs } from "@mui/material"; -import { filterUndefOrNull } from "../../utils/core"; +import { filterUndefOrNull } from "@slub/edb-core-utils"; import { Line, LineChart, Tooltip, XAxis, YAxis } from "recharts"; -import VisTimelineWrapper from "../visTimelineWrapper/VisTimelineWrapper"; import { TimelineItem } from "vis-timeline/types"; -import { - applyToEachField, - extractFieldIfString, -} from "../../utils/mapping/simpleFieldExtractor"; import get from "lodash/get"; import { ListAlt, Polyline, Timeline } from "@mui/icons-material"; +import { useTranslation } from "next-i18next"; +import NiceModal from "@ebay/nice-modal-react"; +import { fixSparqlOrder, withDefaultPrefix } from "@slub/sparql-schema"; +import { IRIToStringFn, PrimaryFieldDeclaration } from "@slub/edb-core-types"; +import { VisTimelineWrapper } from "@slub/edb-vis-timeline"; import { GenericListItem, GenericVirtualizedList, -} from "./GenericVirtualizedList"; -import { useTranslation } from "next-i18next"; -import NiceModal from "@ebay/nice-modal-react"; -import { EntityDetailModal } from "../../form/show"; -import { withDefaultPrefix } from "@slub/sparql-schema"; +} from "@slub/edb-virtualized-components"; const makeFilterUNION2 = (searchString: string, length: number) => { const filterUNION = []; @@ -101,55 +94,13 @@ const personDateToDate = (date: string) => { return null; }; -const itemToTimelineItemGeneric = ( - item: any, - typeIRI: string, - parseStart: (item: any) => Date | null, - parseEnd: (item: any) => Date | null, -): TimelineItem | null => { - const typeName = typeIRItoTypeName(typeIRI); - if (isString(item.entity?.value)) { - const start = parseStart(item); - if (!start) return null; - const end = parseEnd(item); - const primaryField = primaryFields[typeName]; - const content = primaryField ? get(item, primaryField.label)?.value : null; - return { - id: item.entity?.value, - content: content || typeName, - start, - end, - style: "point", //!end || start === end ? 'circle' : 'box', - group: typeName, - }; - } - return null; -}; - -const itemToListItemReal = ( +const itemToListItem = ( item: any, typeIRI: string, + typeIRIToTypeName: IRIToStringFn, + primaryFields: PrimaryFieldDeclaration, ): GenericListItem | null => { - const typeName = typeIRItoTypeName(typeIRI); - if (isString(item.entity?.value)) { - const primaryFieldDeclaration = primaryFields[typeName]; - const { label, description, image } = applyToEachField( - item, - primaryFieldDeclaration, - extractFieldIfString, - ); - return { - id: item.entity.value, - entry: item, - primary: label, - description, - avatar: image, - }; - } - return null; -}; -const itemToListItem = (item: any, typeIRI: string): GenericListItem | null => { - const typeName = typeIRItoTypeName(typeIRI); + const typeName = typeIRIToTypeName(typeIRI); if (isString(item.entity?.value)) { const primaryField = primaryFields[typeName]; const primary = primaryField @@ -172,8 +123,10 @@ const itemToListItem = (item: any, typeIRI: string): GenericListItem | null => { const itemToTimelineItem = ( item: any, typeIRI: string, + typeIRIToTypeName: IRIToStringFn, + primaryFields: PrimaryFieldDeclaration, ): TimelineItem | null => { - const typeName = typeIRItoTypeName(typeIRI); + const typeName = typeIRIToTypeName(typeIRI); if (typeName === "Person") { if (isString(item.birthDate?.value)) { const start = personDateToDate(item.birthDate.value); @@ -224,6 +177,12 @@ const itemToTimelineItem = ( return null; }; export const SearchBar = ({ relevantTypes }: { relevantTypes: string[] }) => { + const { + queryBuildOptions: { primaryFields }, + typeIRIToTypeName, + jsonLDConfig: { defaultPrefix }, + components: { EntityDetailModal }, + } = useAdbContext(); const { t } = useTranslation(); const [selectedId, setSelectedId] = useState(null); const [searchText, setSearchText] = useState(""); @@ -263,7 +222,7 @@ export const SearchBar = ({ relevantTypes }: { relevantTypes: string[] }) => { ); return (await selectFetch(query))?.map((item) => ({ id: item.type?.value, - title: t(typeIRItoTypeName(item.type?.value)), + title: t(typeIRIToTypeName(item.type?.value)), score: parseInt(item.count?.value) || 0, })); }, @@ -282,14 +241,14 @@ export const SearchBar = ({ relevantTypes }: { relevantTypes: string[] }) => { .filter((iri) => !searchResults?.find(({ id }) => id === iri)) .map((iri) => ({ id: iri, - title: t(typeIRItoTypeName(iri)), + title: t(typeIRIToTypeName(iri)), score: 0, })), ], ["title"], ["desc"], ); - }, [t, searchResults, selectedClassIRIs]); + }, [t, searchResults, selectedClassIRIs, typeIRIToTypeName]); const handleTimelineSelect = useCallback( (selection: any) => { @@ -367,10 +326,15 @@ export const SearchBar = ({ relevantTypes }: { relevantTypes: string[] }) => { () => filterUndefOrNull( allExhibitionsData?.map((item) => - itemToTimelineItem(item, item.type.value), + itemToTimelineItem( + item, + item.type.value, + typeIRIToTypeName, + primaryFields, + ), ) || ([] as TimelineItem[]), ), - [allExhibitionsData], + [allExhibitionsData, typeIRIToTypeName, primaryFields], ); const dateScore = useMemo(() => { @@ -399,10 +363,15 @@ export const SearchBar = ({ relevantTypes }: { relevantTypes: string[] }) => { () => filterUndefOrNull( allExhibitionsData?.map((item) => - itemToListItem(item, item.type.value), + itemToListItem( + item, + item.type.value, + typeIRIToTypeName, + primaryFields, + ), ) || ([] as GenericListItem[]), ), - [allExhibitionsData], + [allExhibitionsData, primaryFields, typeIRIToTypeName], ); const [tabIndex, setTabIndex] = useState(0); @@ -411,11 +380,15 @@ export const SearchBar = ({ relevantTypes }: { relevantTypes: string[] }) => { setTabIndex(newTabIndex); }; - const showEntry = useCallback((entityIRI: string) => { - NiceModal.show(EntityDetailModal, { - entityIRI, - }); - }, []); + const showEntry = useCallback( + (entityIRI: string) => { + NiceModal.show(EntityDetailModal, { + entityIRI, + disableInlineEditing: true, + }); + }, + [EntityDetailModal], + ); return ( diff --git a/apps/exhibition-live/components/content/main/TypedForm.tsx b/apps/exhibition-live/components/content/main/TypedForm.tsx index b73e1dca..055a7f86 100644 --- a/apps/exhibition-live/components/content/main/TypedForm.tsx +++ b/apps/exhibition-live/components/content/main/TypedForm.tsx @@ -1,26 +1,21 @@ import { Box, Grid } from "@mui/material"; import { JSONSchema7 } from "json-schema"; import React, { useCallback, useMemo, useState } from "react"; -import { SplitPane } from "react-collapse-pane"; -import { BASE_IRI } from "../../config"; -import { defaultJsonldContext, defaultPrefix } from "../../form/formConfigs"; -import { uischemata } from "../../form/uischemaForType"; -import { uischemas } from "../../form/uischemas"; -import { materialCategorizationStepperLayoutWithPortal } from "../../renderer/MaterialCategorizationStepperLayoutWithPortal"; import { + useAdbContext, useFormEditor, useGlobalSearch, + useModifiedRouter, useRightDrawerState, -} from "../../state"; -import useExtendedSchema from "../../state/useExtendedSchema"; -import { useGlobalCRUDOptions } from "../../state/useGlobalCRUDOptions"; -import { useSettings } from "../../state/useLocalSettings"; -import { encodeIRI, irisToData } from "../../utils/core"; -import NewSemanticJsonForm from "../../form/SemanticJsonForm"; -import { useModifiedRouter } from "../../basic"; -import { EntityDetailElement } from "../../form/show"; -import { RootFormProvider } from "../../provider"; + useSettings, +} from "@slub/edb-state-hooks"; +import { encodeIRI } from "@slub/edb-ui-utils"; +import NewSemanticJsonForm from "../../form/SemanticJsonFormOperational"; +import { useFormDataStore, useExtendedSchema } from "@slub/edb-state-hooks"; +import { useCRUDWithQueryClient } from "@slub/edb-state-hooks"; +import { EntityDetailElement } from "@slub/edb-advanced-components"; +import { materialCategorizationStepperLayoutWithPortal } from "@slub/edb-layout-renderer"; type Props = { children: React.ReactChild; @@ -30,7 +25,7 @@ type Props = { }; const WithPreviewForm = ({ classIRI, entityIRI, data, children }: Props) => { const isLandscape = false; - const { previewEnabled, togglePreview, formData } = useFormEditor(); + const { previewEnabled } = useFormEditor(); const { features } = useSettings(); const { width: rightDrawerWidth, open: rightDrawerOpen } = useRightDrawerState(); @@ -83,8 +78,17 @@ export type MainFormProps = { classIRI: string; }; const TypedForm = ({ typeName, entityIRI, classIRI }: MainFormProps) => { + const { + typeIRIToTypeName, + jsonLDConfig: { defaultPrefix, jsonldContext }, + uischemata, + } = useAdbContext(); //const { formData: data, setFormData: setData } = useFormData(); - const [data, setData] = useState(irisToData(entityIRI, classIRI)); + const { formData: data, setFormData: setData } = useFormDataStore({ + entityIRI, + typeIRI: classIRI, + }); + const { search: searchText } = useGlobalSearch(); const router = useModifiedRouter(); @@ -95,12 +99,12 @@ const TypedForm = ({ typeName, entityIRI, classIRI }: MainFormProps) => { if (!entityIRI || !typeIRI) { return; } - const typeName = typeIRI.substring(BASE_IRI.length, typeIRI.length); + const typeName = typeIRIToTypeName(typeIRI); router.push(`/create/${typeName}?encID=${encodeIRI(entityIRI)}`); }, - [router], + [router, typeIRIToTypeName], ); - const loadedSchema = useExtendedSchema({ typeName, classIRI }); + const loadedSchema = useExtendedSchema({ typeName }); const { width: rightDrawerWidth, open: rightDrawerOpen } = useRightDrawerState(); @@ -111,10 +115,13 @@ const TypedForm = ({ typeName, entityIRI, classIRI }: MainFormProps) => { //const { stepperRef, actionRef } = useFormRefsContext(); const handleChangeData = useCallback( - (data: any) => { - setData(data); + (_data: any) => { + if (typeof _data === "function") { + const newData = _data(data); + setData(newData); + } else setData(_data); }, - [setData], + [setData, data], ); const mainFormRenderers = useMemo(() => { return [ @@ -123,41 +130,38 @@ const TypedForm = ({ typeName, entityIRI, classIRI }: MainFormProps) => { ]; }, []); - const uischema = useMemo( - () => uischemata[typeName] || (uischemas as any)[typeName], - [typeName], - ); + const uischema = useMemo(() => uischemata?.[typeName], [typeName]); return ( - - - {loadedSchema && ( - - - - )} - - + + {loadedSchema && ( + + + + )} + ); }; diff --git a/apps/exhibition-live/components/content/main/TypedInfiniteList.tsx b/apps/exhibition-live/components/content/main/TypedInfiniteList.tsx deleted file mode 100644 index 2b87cc34..00000000 --- a/apps/exhibition-live/components/content/main/TypedInfiniteList.tsx +++ /dev/null @@ -1,464 +0,0 @@ -import { - defaultPrefix, - defaultQueryBuilderOptions, - sladb, - slent, -} from "../../form/formConfigs"; -import { useCallback, useEffect, useMemo, useRef, useState } from "react"; -import schema from "../../../public/schema/Exhibition.schema.json"; -import { v4 as uuidv4 } from "uuid"; -import { useGlobalCRUDOptions } from "../../state/useGlobalCRUDOptions"; -import { jsonSchema2Select } from "../../utils/sparql"; -import { - Box, - Link, - Skeleton, - MenuItem, - ListItemIcon, - Backdrop, - CircularProgress, -} from "@mui/material"; -import { - MaterialReactTable, - MRT_ColumnDef, - MRT_EditActionButtons, - MRT_SortingState, - MRT_Virtualizer, -} from "material-react-table"; -import { encodeIRI } from "../../utils/core"; -import { JSONSchema7 } from "json-schema"; -import { Add, Details, Edit } from "@mui/icons-material"; -import { useRouter } from "next/router"; -import { primaryFields } from "../../config"; -import { useInfiniteQuery, useMutation, useQuery } from "@tanstack/react-query"; -import { SemanticFormsModal } from "../../renderer/SemanticFormsModal"; -import NiceModal from "@ebay/nice-modal-react"; -import GenericModal from "../../form/GenericModal"; -import { useSnackbar } from "notistack"; -import { JsonSchema } from "@jsonforms/core"; -import useExtendedSchema from "../../state/useExtendedSchema"; -import Button from "@mui/material/Button"; -import { flatten } from "lodash"; -import get from "lodash/get"; -import { useModifiedRouter } from "../../basic"; -import { remove, withDefaultPrefix } from "@slub/sparql-schema"; -import { - filterForArrayProperties, - filterForPrimitiveProperties, - isJSONSchema, -} from "@slub/json-schema-utils"; -import { parseMarkdownLinks } from "@slub/edb-core-utils"; - -type Props = { - typeName: string; -}; - -const p = (path: string[]) => path.join("_"); - -const mkAccessor = - (path: string, defaultValue?: string | any) => (row: any) => { - return get(row, path, defaultValue || ""); - }; -const computeColumns: ( - schema: JSONSchema7, - path?: string[], -) => MRT_ColumnDef[] = (schema: JSONSchema7, path: string[] = []) => - (!schema?.properties - ? [] - : [ - /*{ - id: p([...path, "id"]) - header: p([...path, "id"]), - accessorKey: `${p([...path, "entry"])}.value`, - },*/ - ...Object.keys(filterForPrimitiveProperties(schema.properties)).map( - (key) => ({ - header: p([...path, key]), - id: p([...path, key, "single"]), - accessorFn: mkAccessor(`${p([...path, key, "single"])}.value`, ""), - Cell: ({ cell }) => <>{cell.getValue() ?? ""}, - }), - ), - ...Object.entries(schema.properties || {}) - .filter( - ([, value]) => - typeof value === "object" && - value.type === "object" && - !value.$ref, - ) - .map(([key, value]) => - isJSONSchema(value) ? computeColumns(value, [...path, key]) : [], - ) - .flat(), - ...Object.keys(filterForArrayProperties(schema.properties)).flatMap( - (key) => [ - { - header: p([...path, key]) + " count", - id: p([...path, key, "count"]), - accessorFn: mkAccessor( - `${(p([...path, key, "count"]), 0)}.value`, - ), - Cell: ({ cell }) => ( - {cell.getValue() ?? 0} - ), - }, - { - header: p([...path, key]), - id: p([...path, key, "label_group"]), - accessorFn: mkAccessor( - `${(p([...path, key, "label_group"]), "")}.value`, - ), - Cell: ({ cell }) => ( - <> - {cell.getValue() && - parseMarkdownLinks(cell.getValue()).map( - ({ label, url }) => { - return ( - - {" "} - - {label} - {" "} - - ); - }, - )} - - ), - }, - ], - ), - ]) as any as MRT_ColumnDef[]; - -const defsFieldName = (schema as JSONSchema7).definitions - ? "definitions" - : "$defs"; -export const TypedInfiniteList = ({ typeName }: Props) => { - const classIRI = useMemo(() => { - return sladb(typeName).value; - }, [typeName]); - const loadedSchema = useMemo( - () => - ({ ...schema, ...schema[defsFieldName][typeName] }) as - | JSONSchema7 - | undefined, - [typeName], - ); - - const [pagination, setPagination] = useState({ - pageIndex: 0, - pageSize: 100, - }); - - const [sorting, setSorting] = useState([ - { id: "entity", desc: false }, - ]); - - const handleColumnOrderChange = useCallback( - (s: MRT_SortingState) => { - setSorting(s); - }, - [setSorting], - ); - - const { crudOptions } = useGlobalCRUDOptions(); - - const { data: resultListData, isLoading } = useQuery( - ["allEntries", classIRI, sorting], - async () => { - const sparqlQuery = withDefaultPrefix( - defaultPrefix, - jsonSchema2Select(loadedSchema, classIRI, [], { - primaryFields: primaryFields, - orderBy: sorting.map((s) => ({ orderBy: s.id, descending: s.desc })), - }), - ); - if (!sparqlQuery || !crudOptions?.selectFetch) { - return; - } - const res = await crudOptions.selectFetch(sparqlQuery, { - withHeaders: true, - }); - return res; - }, - { enabled: !!crudOptions?.selectFetch }, - ); - - const resultList = useMemo( - () => resultListData?.results?.bindings ?? [], - [resultListData], - ); - const headerVars = useMemo( - () => resultListData?.head?.vars, - [resultListData], - ); - - const columns = useMemo[]>( - () => computeColumns(loadedSchema), - [loadedSchema], - ); - - const displayColumns = useMemo[]>( - () => columns.filter((col) => !headerVars || headerVars.includes(col.id)), - [columns, headerVars], - ); - - const router = useModifiedRouter(); - const editEntry = useCallback( - (id: string) => { - router.push(`/create/${typeName}?encID=${encodeIRI(id)}`); - }, - [router, typeName], - ); - const extendedSchema = useExtendedSchema({ typeName, classIRI }); - const { mutate: removeEntity } = useMutation( - ["remove", (id: string) => id], - async (id: string) => { - if (!id || !crudOptions.updateFetch) - throw new Error("entityIRI or updateFetch is not defined"); - return remove(id, classIRI, loadedSchema, crudOptions.updateFetch, { - defaultPrefix, - queryBuildOptions: defaultQueryBuilderOptions, - }); - }, - ); - const { enqueueSnackbar } = useSnackbar(); - const handleRemove = useCallback( - async (id: string) => { - NiceModal.show(GenericModal, { - type: "delete", - }).then(() => { - removeEntity(id); - enqueueSnackbar("Removed", { variant: "success" }); - }); - }, - [removeEntity, enqueueSnackbar], - ); - - const tableContainerRef = useRef(null); //we can get access to the underlying TableContainer element and react to its scroll events - const rowVirtualizerInstanceRef = - useRef>(null); //we can get access to the underlying Virtualizer instance and call its scrollToIndex method - - const { - data, - fetchNextPage, - isError, - isFetching, - isLoading: isInfiniteLoading, - } = useInfiniteQuery( - ["infiniteEntries", classIRI, sorting, pagination], - async ({ pageParam = 0 }) => { - if (!loadedSchema || !classIRI) return []; - const sparqlQuery = withDefaultPrefix( - defaultPrefix, - jsonSchema2Select(loadedSchema, classIRI, [], { - primaryFields: primaryFields, - orderBy: sorting.map((s) => ({ orderBy: s.id, descending: s.desc })), - limit: pagination.pageSize, - offset: pageParam * pagination.pageSize + 1, - }), - ); - console.log(sparqlQuery); - if (!sparqlQuery || !crudOptions?.selectFetch) { - return []; - } - const res = await crudOptions.selectFetch(sparqlQuery, { - withHeaders: false, - }); - console.log({ res }); - return res || []; - }, - { - getNextPageParam: (_lastGroup, groups) => groups.length, - refetchOnWindowFocus: false, - enabled: !!classIRI && !!crudOptions?.selectFetch, - }, - ); - const flatData = useMemo( - () => (data?.pages ? flatten(data?.pages) : []), - [data], - ); - const totalFetched = useMemo(() => flatData?.length || 0, [flatData]); - - useEffect(() => { - //scroll to the top of the table when the sorting changes - try { - rowVirtualizerInstanceRef.current?.scrollToIndex?.(0); - } catch (error) { - console.error(error); - } - }, [sorting, pagination]); - - //called on scroll and possibly on mount to fetch more data as the user scrolls and reaches bottom of table - const fetchMoreOnBottomReached = useCallback( - (containerRefElement?: HTMLDivElement | null) => { - if (containerRefElement) { - const { scrollHeight, scrollTop, clientHeight } = containerRefElement; - //once the user has scrolled within 400px of the bottom of the table, fetch more data if we can - if ( - scrollHeight - scrollTop - clientHeight < 400 && - !isFetching && - totalFetched < 10000 - ) { - fetchNextPage(); - } - } - }, - [fetchNextPage, isFetching, totalFetched], - ); - //a check on mount to see if the table is already scrolled to the bottom and immediately needs to fetch more data - useEffect(() => { - fetchMoreOnBottomReached(tableContainerRef.current); - }, [fetchMoreOnBottomReached]); - - return ( - - {columns.length <= 0 ? ( - - ) : ( - <> - theme.zIndex.drawer + 1 }} - open={isLoading} - > - - - - fetchMoreOnBottomReached(event.target as HTMLDivElement), //add an event listener to the table container element - }} - rowVirtualizerOptions={{ overscan: 4 }} - enableColumnVirtualization={true} - enableColumnOrdering //enable some features - enableRowSelection - manualPagination={true} - manualSorting={true} - onSortingChange={handleColumnOrderChange} - initialState={{ - columnVisibility: { id: false, externalId_single: false }, - }} - onPaginationChange={setPagination} - rowCount={resultList.length * 3} - enableRowActions={true} - renderCreateRowDialogContent={({ - table, - row, - internalEditComponents, - }) => { - return ( - table.setCreatingRow(row)} - schema={extendedSchema as JsonSchema} - entityIRI={slent(uuidv4()).value} - typeIRI={classIRI} - > - - - ); - }} - renderEditRowDialogContent={({ - table, - row, - internalEditComponents, - }) => { - return ( - table.setEditingRow(row)} - schema={extendedSchema as JsonSchema} - entityIRI={row.id} - typeIRI={classIRI} - > - - - ); - }} - renderTopToolbarCustomActions={({ table }) => ( - - - - )} - getRowId={(row) => (row as any)?.entity?.value || uuidv4()} - renderRowActionMenuItems={(row) => { - return [ - { - // View profile logic... - row.closeMenu(); - editEntry(row.row.id); - }} - sx={{ m: 0 }} - > - - - - bearbeiten - , - { - row.closeMenu(); - }} - sx={{ m: 0 }} - > - -
- - Details - , - ]; - }} - state={{ - pagination, - sorting, - }} - /> - - )} - - ); -}; - -/* -const ListDebuggingTools = ({ jsonData }: ListDebuggingToolsProps) => { - const { features } = useSettings(); - const { doLocalQuery } = useGlobalCRUDOptions(); - if (!features?.enableDebug) return null; - return ( - - - - - List all {typeName} here. -
{sparqlQuery}
- RESULT: - lvl < 3} /> -
) -}*/ diff --git a/apps/exhibition-live/components/content/settings/AuthorityConfigForm.tsx b/apps/exhibition-live/components/content/settings/AuthorityConfigForm.tsx index a916078d..e83befde 100644 --- a/apps/exhibition-live/components/content/settings/AuthorityConfigForm.tsx +++ b/apps/exhibition-live/components/content/settings/AuthorityConfigForm.tsx @@ -9,7 +9,7 @@ import { Box } from "@mui/system"; import { JSONSchema7 } from "json-schema"; import React, { FunctionComponent, useCallback, useEffect } from "react"; -import { useSettings } from "../../state/useLocalSettings"; +import { useSettings } from "@slub/edb-state-hooks"; interface OwnProps {} diff --git a/apps/exhibition-live/components/content/settings/EndpointChooser.tsx b/apps/exhibition-live/components/content/settings/EndpointChooser.tsx index c5889830..cc3d8b84 100644 --- a/apps/exhibition-live/components/content/settings/EndpointChooser.tsx +++ b/apps/exhibition-live/components/content/settings/EndpointChooser.tsx @@ -7,9 +7,9 @@ import { JsonForms } from "@jsonforms/react"; import { Typography } from "@mui/material"; import { Box } from "@mui/system"; import { JSONSchema7 } from "json-schema"; -import React, { FunctionComponent, useCallback } from "react"; +import React, { FunctionComponent, useCallback, useMemo } from "react"; -import { useSettings } from "../../state/useLocalSettings"; +import { useSettings } from "@slub/edb-state-hooks"; interface OwnProps {} @@ -42,6 +42,9 @@ const schema: JsonSchema = { { const: "qlever", }, + { + const: "rest", + }, { const: "worker", }, @@ -67,7 +70,7 @@ const schema: JsonSchema = { }; const EndpointChooser: FunctionComponent = (props) => { - const { sparqlEndpoints, setSparqlEndpoints } = useSettings(); + const { sparqlEndpoints, setSparqlEndpoints, lockedEndpoint } = useSettings(); const handleFormChange = useCallback( (state: Pick) => { @@ -75,17 +78,22 @@ const EndpointChooser: FunctionComponent = (props) => { }, [setSparqlEndpoints], ); + + const readOnly = useMemo(() => !!lockedEndpoint, [lockedEndpoint]); return ( - - Knowledge Base - SPARQL Endpunkte - - + !readOnly && ( + + Knowledge Base - SPARQL Endpunkte + + + ) ); }; diff --git a/apps/exhibition-live/components/content/settings/FeatureForm.tsx b/apps/exhibition-live/components/content/settings/FeatureForm.tsx index 8b0352f8..50f1645f 100644 --- a/apps/exhibition-live/components/content/settings/FeatureForm.tsx +++ b/apps/exhibition-live/components/content/settings/FeatureForm.tsx @@ -8,7 +8,7 @@ import { Typography } from "@mui/material"; import { Box } from "@mui/system"; import React, { FunctionComponent, useCallback } from "react"; -import { useSettings } from "../../state/useLocalSettings"; +import { useSettings } from "@slub/edb-state-hooks"; interface OwnProps {} @@ -24,6 +24,9 @@ const schema: JsonSchema = { enablePreview: { type: "boolean", }, + enableStylizedCard: { + type: "boolean", + }, }, }; @@ -36,17 +39,18 @@ const FeatureForm: FunctionComponent = (props) => { }, [setFeatures], ); - // a REACT MUI paper list with checkboxes return ( Funktionen - + {features && ( + + )} ); }; diff --git a/apps/exhibition-live/components/content/settings/GoogleDriveSettingsForm.tsx b/apps/exhibition-live/components/content/settings/GoogleDriveSettingsForm.tsx index f4270f0f..0324de08 100644 --- a/apps/exhibition-live/components/content/settings/GoogleDriveSettingsForm.tsx +++ b/apps/exhibition-live/components/content/settings/GoogleDriveSettingsForm.tsx @@ -8,7 +8,7 @@ import { Typography } from "@mui/material"; import { Box } from "@mui/system"; import React, { FunctionComponent, useCallback } from "react"; -import { useSettings } from "../../state/useLocalSettings"; +import { useSettings } from "@slub/edb-state-hooks"; interface OwnProps {} diff --git a/apps/exhibition-live/components/content/settings/OpenAISettingsForm.tsx b/apps/exhibition-live/components/content/settings/OpenAISettingsForm.tsx index 3f72d5c3..0b3c116a 100644 --- a/apps/exhibition-live/components/content/settings/OpenAISettingsForm.tsx +++ b/apps/exhibition-live/components/content/settings/OpenAISettingsForm.tsx @@ -8,7 +8,7 @@ import { Typography } from "@mui/material"; import { Box } from "@mui/system"; import React, { FunctionComponent, useCallback } from "react"; -import { useSettings } from "../../state/useLocalSettings"; +import { useSettings } from "@slub/edb-state-hooks"; interface OwnProps {} diff --git a/apps/exhibition-live/components/content/settings/SettingsModal.tsx b/apps/exhibition-live/components/content/settings/SettingsModal.tsx index 25d82a83..a71a2e9a 100644 --- a/apps/exhibition-live/components/content/settings/SettingsModal.tsx +++ b/apps/exhibition-live/components/content/settings/SettingsModal.tsx @@ -17,7 +17,7 @@ import { useTheme } from "@mui/material/styles"; import useMediaQuery from "@mui/material/useMediaQuery"; import React, { FunctionComponent, useCallback, useState } from "react"; -import { useLocalSettings } from "../../state/useLocalSettings"; +import { useLocalSettings } from "@slub/edb-state-hooks"; import AuthorityConfigForm from "./AuthorityConfigForm"; import EndpointChooser from "./EndpointChooser"; import FeatureForm from "./FeatureForm"; diff --git a/apps/exhibition-live/components/exhibtion/prefixes.ts b/apps/exhibition-live/components/exhibtion/prefixes.ts deleted file mode 100644 index 68d39621..00000000 --- a/apps/exhibition-live/components/exhibtion/prefixes.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Prefixes } from "@slub/edb-core-types"; - -export const exhibitionPrefixes: Prefixes = { - sladb: "http://ontologies.slub-dresden.de/exhibition#", - slent: "http://ontologies.slub-dresden.de/exhibition/entity#", - slsrc: "http://ontologies.slub-dresden.de/source#", - slmeta: "http://ontologies.slub-dresden.de/meta#", - slperson: "http://ontologies.slub-dresden.de/person#", -}; diff --git a/apps/exhibition-live/components/form/EditExhibitionJSONForm.stories.tsx b/apps/exhibition-live/components/form/EditExhibitionJSONForm.stories.tsx index 5101cfe8..313519ad 100644 --- a/apps/exhibition-live/components/form/EditExhibitionJSONForm.stories.tsx +++ b/apps/exhibition-live/components/form/EditExhibitionJSONForm.stories.tsx @@ -1,22 +1,18 @@ -import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { QueryClient, QueryClientProvider } from "@slub/edb-state-hooks"; import { JSONSchema7 } from "json-schema"; -import { useState } from "react"; +import { useMemo, useState } from "react"; -import schema from "../../public/schema/Exhibition.schema.json"; -import useExtendedSchema from "../state/useExtendedSchema"; -import { useSettings } from "../state/useLocalSettings"; import { defaultJsonldContext, defaultPrefix, sladb, slent, -} from "./formConfigs"; -import NewSemanticJsonForm from "./SemanticJsonForm"; -import { oxigraphCrudOptions } from "@slub/remote-query-implementations"; +} from "../config/formConfigs"; +import NewSemanticJsonForm from "./SemanticJsonFormOperational"; +import { useExtendedSchema } from "@slub/edb-state-hooks"; +import { uischemata } from "../config/uischemata"; -export const queryClient = new QueryClient(); - -const exhibitionSchema = { ...schema, ...schema.$defs.Exhibition }; +const queryClient = new QueryClient(); const classIRI = sladb.Exhibition.value; const exampleData = { @@ -28,7 +24,8 @@ const exampleData = { const SemanticJsonFormOneShot = () => { const [data, setData] = useState(exampleData); const typeName = "Exhibition"; - const loadedSchema = useExtendedSchema({ typeName, classIRI }); + const loadedSchema = useExtendedSchema({ typeName }); + const uischema = useMemo(() => uischemata?.[typeName], [typeName]); return ( { shouldLoadInitially jsonldContext={defaultJsonldContext} schema={loadedSchema as JSONSchema7} - jsonFormsProps={{}} + jsonFormsProps={{ + uischema, + }} /> ); }; @@ -60,6 +59,6 @@ export const SemanticJsonFormExhibition = () => { ); }; export default { - title: "form/exhibition/EditExhibitionJSONForm", + title: "ui/form/EditExhibitionJSONForm", component: NewSemanticJsonForm, }; diff --git a/apps/exhibition-live/components/form/Form.stories.tsx b/apps/exhibition-live/components/form/Form.stories.tsx index abe8aee5..c2205eee 100644 --- a/apps/exhibition-live/components/form/Form.stories.tsx +++ b/apps/exhibition-live/components/form/Form.stories.tsx @@ -1,23 +1,35 @@ import TypedForm from "../content/main/TypedForm"; -import { sladb } from "./formConfigs"; +import { sladb } from "../config/formConfigs"; export default { - title: "forms/Form", + title: "ui/form/Examples", component: TypedForm, }; export const TagForm = () => (
- +
); export const LocationForm = () => (
- +
); export const PlaceForm = () => (
- +
); diff --git a/apps/exhibition-live/components/form/SemanticJsonFormNoOps.tsx b/apps/exhibition-live/components/form/SemanticJsonFormNoOps.tsx deleted file mode 100644 index e04c4c79..00000000 --- a/apps/exhibition-live/components/form/SemanticJsonFormNoOps.tsx +++ /dev/null @@ -1,344 +0,0 @@ -import "react-json-view-lite/dist/index.css"; - -import { - and, - isObjectArray, - isObjectArrayControl, - JsonFormsCore, - JsonSchema, - rankWith, - schemaMatches, - scopeEndsWith, - UISchemaElement, -} from "@jsonforms/core"; -import { - materialCells, - materialRenderers, -} from "@jsonforms/material-renderers"; -import { JsonForms, JsonFormsInitStateProps } from "@jsonforms/react"; -import { Card, CardContent, Grid } from "@mui/material"; -import { JSONSchema7 } from "json-schema"; -import { isEmpty, mixin, merge, assign } from "lodash"; -import React, { FunctionComponent, useCallback, useMemo } from "react"; - -import AdbSpecialDateRenderer, { - adbSpecialDateControlTester, -} from "../renderer/AdbSpecialDateRenderer"; -import AutoIdentifierRenderer from "../renderer/AutoIdentifierRenderer"; -import ImageRenderer from "../renderer/ImageRenderer"; -import InlineCondensedSemanticFormsRenderer from "../renderer/InlineCondensedSemanticFormsRenderer"; -import MaterialArrayOfLinkedItemRenderer from "../renderer/MaterialArrayOfLinkedItemRenderer"; -import MaterialCustomAnyOfRenderer, { - materialCustomAnyOfControlTester, -} from "../renderer/MaterialCustomAnyOfRenderer"; -import MaterialLinkedObjectRenderer, { - materialLinkedObjectControlTester, -} from "../renderer/MaterialLinkedObjectRenderer"; -import TypeOfRenderer from "../renderer/TypeOfRenderer"; -import SimilarityFinder from "./SimilarityFinder"; -import { SearchbarWithFloatingButton } from "../layout/main-layout/Searchbar"; -import MaterialBooleanControl, { - materialBooleanControlTester, -} from "../renderer/MaterialBooleanControl"; -import { primaryFields, typeIRItoTypeName } from "../config"; -import NiceModal from "@ebay/nice-modal-react"; -import GenericModal from "./GenericModal"; -import { - primaryTextFieldControlTester, - PrimaryTextFieldRenderer, -} from "../renderer/PrimaryFieldTextRenderer"; -import { useGlobalSearch, useRightDrawerState } from "../state"; -import MaterialArrayOfLinkedItemChipsRenderer, { - materialArrayLayoutChipsTester, -} from "../renderer/MaterialArrayOfLinkedItemChipsRenderer"; -import InlineDropdownRenderer from "../renderer/InlineDropdownRenderer"; -import { ErrorObject } from "ajv"; -import { OptionsModal } from "./OptionsModal"; -import { useTranslation } from "next-i18next"; - -export type CRUDOpsType = { - load: () => Promise; - save: () => Promise; - remove: () => Promise; -}; - -export type ChangeCause = "user" | "mapping" | "reload"; - -export interface SemanticJsonFormsNoOpsProps { - typeIRI: string; - data: any; - onChange?: (data: any, reason: ChangeCause) => void; - onError?: (errors: ErrorObject[]) => void; - schema: JSONSchema7; - jsonFormsProps?: Partial; - onEntityChange?: (entityIRI: string | undefined) => void; - onEntityDataChange?: (entityData: any) => void; - toolbar?: React.ReactNode; - forceEditMode?: boolean; - defaultEditMode?: boolean; - searchText?: string; - disableSimilarityFinder?: boolean; - enableSidebar?: boolean; - wrapWithinCard?: boolean; - formsPath?: string; -} - -const renderers = [ - ...materialRenderers, - { - tester: materialCustomAnyOfControlTester, - renderer: MaterialCustomAnyOfRenderer, - }, - { - tester: rankWith(10, scopeEndsWith("image")), - renderer: ImageRenderer, - }, - { - tester: rankWith(10, scopeEndsWith("@id")), - renderer: AutoIdentifierRenderer, - }, - { - tester: rankWith(10, scopeEndsWith("@type")), - renderer: TypeOfRenderer, - }, - { - tester: rankWith( - 5, - and( - isObjectArray, - schemaMatches((schema) => { - if ( - !( - schema.type === "array" && - typeof schema.items === "object" && - (schema.items as JSONSchema7).properties - ) - ) { - return Boolean((schema.items as JSONSchema7).$ref); - } - const props = (schema.items as JSONSchema7).properties; - return Boolean(props["@id"] && props["@type"]); - }), - ), - ), - renderer: MaterialArrayOfLinkedItemRenderer, - }, - { - tester: materialArrayLayoutChipsTester, - renderer: MaterialArrayOfLinkedItemChipsRenderer, - }, - { - tester: rankWith(14, (uischema: UISchemaElement, schema, ctx): boolean => { - if (isEmpty(uischema) || isObjectArrayControl(uischema, schema, ctx)) { - return false; - } - const options = uischema.options; - return !isEmpty(options) && options["inline"]; - }), - renderer: InlineCondensedSemanticFormsRenderer, - }, - { - tester: rankWith(15, (uischema: UISchemaElement, schema, ctx): boolean => { - if (isEmpty(uischema) || isObjectArrayControl(uischema, schema, ctx)) { - return false; - } - const options = uischema.options; - return !isEmpty(options) && options["dropdown"] === true; - }), - renderer: InlineDropdownRenderer, - }, - { - tester: materialLinkedObjectControlTester, - renderer: MaterialLinkedObjectRenderer, - }, - { - tester: adbSpecialDateControlTester, - renderer: AdbSpecialDateRenderer, - }, - { - tester: materialBooleanControlTester, - renderer: MaterialBooleanControl, - }, -]; - -export const SemanticJsonFormNoOps: FunctionComponent< - SemanticJsonFormsNoOpsProps -> = ({ - data, - onChange, - onError, - typeIRI, - schema, - jsonFormsProps = {}, - onEntityDataChange, - toolbar, - searchText, - disableSimilarityFinder, - enableSidebar, - wrapWithinCard, - formsPath, -}) => { - const searchOnDataPath = useMemo(() => { - const typeName = typeIRItoTypeName(typeIRI); - return primaryFields[typeName]?.label; - }, [typeIRI]); - const primaryFieldRenderer = useMemo( - () => - primaryFields[typeIRItoTypeName(typeIRI)]?.label - ? [ - { - tester: primaryTextFieldControlTester(typeIRItoTypeName(typeIRI)), - renderer: PrimaryTextFieldRenderer, - }, - ] - : [], - [typeIRI], - ); - - const handleFormChange = useCallback( - (state: Pick) => { - onChange && onChange(state.data, "user"); - if (onError) onError(state.errors || []); - }, - [onChange, onError], - ); - - const { closeDrawer } = useRightDrawerState(); - const { t } = useTranslation(); - - const handleMappedData = useCallback( - (newData: any) => { - if (!newData) return; - //avoid overriding of id and type by mapped data - NiceModal.show(OptionsModal, { - id: "confirm-mapping-dialog", - content: { - title: t("merge-or-replace"), - text: t("confirm-mapping-dialog-message"), - }, - options: [ - { - title: t("replace data"), - value: "replace", - }, - { - title: t("merge data"), - value: "merge", - }, - ], - }).then((decision: string) => { - closeDrawer(); - onChange((data: any) => { - console.log({ data, newData, decision }); - if (decision === "replace") { - return { - ...newData, - "@id": data["@id"], - "@type": data["@type"], - }; - } - return merge(data, { - ...newData, - "@id": data["@id"], - "@type": data["@type"], - }); - }, "mapping"); - }); - }, - [onChange, closeDrawer, t], - ); - - const handleEntityIRIChange = useCallback( - (iri) => { - onEntityDataChange && - onEntityDataChange({ "@id": iri, "@type": typeIRI }); - closeDrawer(); - }, - [onEntityDataChange, typeIRI, closeDrawer], - ); - - const WithCard = useMemo( - () => - ({ children }: { children: React.ReactNode }) => - wrapWithinCard ? ( - - {children} - - ) : ( - children - ), - [wrapWithinCard], - ); - const { renderers: jfpRenderers, config, ...jfpProps } = jsonFormsProps; - const finalJsonFormsProps = { - ...jfpProps, - config: { - ...config, - formsPath, - typeIRI, - }, - }; - const allRenderer = useMemo( - () => [...renderers, ...(jfpRenderers || []), ...primaryFieldRenderer], - [jfpRenderers, primaryFieldRenderer], - ); - const { path: globalPath } = useGlobalSearch(); - - return ( - - - - - - {toolbar ? toolbar : null} - - - - {!disableSimilarityFinder && !enableSidebar && searchText && ( - - - - )} - - - {formsPath === globalPath && ( - - - - {" "} - - )} - - ); -}; diff --git a/apps/exhibition-live/components/form/SemanticJsonForm.tsx b/apps/exhibition-live/components/form/SemanticJsonFormOperational.tsx similarity index 77% rename from apps/exhibition-live/components/form/SemanticJsonForm.tsx rename to apps/exhibition-live/components/form/SemanticJsonFormOperational.tsx index 1c8ef007..49aa4192 100644 --- a/apps/exhibition-live/components/form/SemanticJsonForm.tsx +++ b/apps/exhibition-live/components/form/SemanticJsonFormOperational.tsx @@ -1,9 +1,6 @@ import "react-json-view-lite/dist/index.css"; import NiceModal from "@ebay/nice-modal-react"; -import { JsonFormsInitStateProps } from "@jsonforms/react"; -import { JSONSchema7 } from "json-schema"; -import { JsonLdContext } from "jsonld-context-parser"; import React, { FunctionComponent, useCallback, @@ -12,49 +9,19 @@ import React, { useState, } from "react"; -import { CRUDOptions } from "../state/useSPARQL_CRUD"; -import { FormDebuggingTools } from "./FormDebuggingTools"; -import GenericModal from "./GenericModal"; -import { cleanJSONLD } from "../utils/crud"; -import { useCRUDWithQueryClient } from "../state/useCRUDWithQueryClient"; +import { useAdbContext, useCRUDWithQueryClient } from "@slub/edb-state-hooks"; import { useSnackbar } from "notistack"; -import { ChangeCause, SemanticJsonFormNoOps } from "./SemanticJsonFormNoOps"; import { SemanticJsonFormToolbar } from "./SemanticJsonFormToolbar"; -import { useSettings } from "../state/useLocalSettings"; -import { useLoadQuery, useQueryKeyResolver } from "../state"; +import { useSettings } from "@slub/edb-state-hooks"; +import { useQueryKeyResolver } from "@slub/edb-state-hooks"; import { Backdrop, Box, CircularProgress } from "@mui/material"; -import { EntityDetailModal } from "./show"; import { create } from "zustand"; import { useTranslation } from "next-i18next"; - -export type CRUDOpsType = { - load: () => Promise; - save: () => Promise; - remove: () => Promise; -}; - -export interface SemanticJsonFormsProps { - entityIRI?: string | undefined; - data: any; - onChange: (data: any) => void; - shouldLoadInitially?: boolean; - typeIRI: string; - schema: JSONSchema7; - jsonldContext: JsonLdContext; - debugEnabled?: boolean; - jsonFormsProps?: Partial; - onEntityChange?: (entityIRI: string | undefined) => void; - onEntityDataChange?: (entityData: any) => void; - defaultPrefix: string; - hideToolbar?: boolean; - forceEditMode?: boolean; - defaultEditMode?: boolean; - searchText?: string; - toolbarChildren?: React.ReactNode; - disableSimilarityFinder?: boolean; - enableSidebar?: boolean; - wrapWithinCard?: boolean; -} +import { cleanJSONLD, LoadResult } from "@slub/sparql-schema"; +import { FormDebuggingTools } from "@slub/edb-debug-utils"; +import { SemanticJsonFormProps } from "@slub/edb-global-types"; +import { GenericModal } from "@slub/edb-basic-components"; +import { ChangeCause } from "@slub/edb-linked-data-renderer"; type SemanticJsonFormStateType = { isSaving: boolean; @@ -83,7 +50,7 @@ const useSemanticJsonFormState = create( }, }), ); -const SemanticJsonForm: FunctionComponent = ({ +const SemanticJsonFormOperational: FunctionComponent = ({ entityIRI, data, onChange, @@ -108,15 +75,17 @@ const SemanticJsonForm: FunctionComponent = ({ ); const { enqueueSnackbar } = useSnackbar(); - const { saveMutation, removeMutation } = useCRUDWithQueryClient( + const { + components: { EntityDetailModal, SemanticJsonForm }, + } = useAdbContext(); + + const { saveMutation, removeMutation, loadEntity } = useCRUDWithQueryClient({ entityIRI, typeIRI, schema, - { enabled: false }, - "rootLoad", - ); - - const loadEntity = useLoadQuery(defaultPrefix, "rootLoad"); + queryOptions: { enabled: false }, + loadQueryKey: "rootLoad", + }); const { updateSourceToTargets, removeSource } = useQueryKeyResolver(); const [isSaving, setIsSaving] = useState(false); @@ -128,12 +97,10 @@ const SemanticJsonForm: FunctionComponent = ({ const refetch = useCallback( () => - loadEntity(entityIRI, typeIRI, schema).then((loadResult) => { - if (loadResult.document) { - console.log("(refetch) result from root load"); + loadEntity(entityIRI, typeIRI).then((loadResult: LoadResult | null) => { + if (loadResult !== null && loadResult?.document) { const data = loadResult.document; updateSourceToTargets(entityIRI, loadResult.subjects); - if (!data["@id"] || !data["@type"]) return; onChange(data); return data; } @@ -258,7 +225,7 @@ const SemanticJsonForm: FunctionComponent = ({ entityIRI: entityIRI, readonly: true, }); - }, [typeIRI, entityIRI]); + }, [typeIRI, entityIRI, EntityDetailModal]); const handleOnChange = useCallback( (data: any, reason: ChangeCause) => { @@ -281,7 +248,7 @@ const SemanticJsonForm: FunctionComponent = ({ > - = ({ ); }; -export default SemanticJsonForm; +export default SemanticJsonFormOperational; diff --git a/apps/exhibition-live/components/form/SemanticJsonFormToolbar.tsx b/apps/exhibition-live/components/form/SemanticJsonFormToolbar.tsx index a59f223d..e725d0d9 100644 --- a/apps/exhibition-live/components/form/SemanticJsonFormToolbar.tsx +++ b/apps/exhibition-live/components/form/SemanticJsonFormToolbar.tsx @@ -9,6 +9,7 @@ import { Save, } from "@mui/icons-material"; import React from "react"; +import { useTranslation } from "next-i18next"; type SemanticJsonFormsToolbarProps = { editMode: boolean; @@ -30,6 +31,7 @@ export const SemanticJsonFormToolbar = ({ onShow, children, }: SemanticJsonFormsToolbarProps) => { + const { t } = useTranslation(); return ( @@ -41,22 +43,22 @@ export const SemanticJsonFormToolbar = ({ {editMode && ( <> {onSave && ( - + )} {onRemove && ( - + )} {onReload && ( - + )} {onReset && ( - + )} diff --git a/apps/exhibition-live/components/form/SimilarityFinder.tsx b/apps/exhibition-live/components/form/SimilarityFinder.tsx deleted file mode 100644 index 5e242d1b..00000000 --- a/apps/exhibition-live/components/form/SimilarityFinder.tsx +++ /dev/null @@ -1,966 +0,0 @@ -import { Resolve } from "@jsonforms/core"; -import { - Check, - NoteAdd, - Storage as KnowledgebaseIcon, -} from "@mui/icons-material"; -import { - Badge, - Box, - Button, - Divider, - Grid, - Hidden, - IconButton, - List, - Stack, - TextField, - TextFieldProps, -} from "@mui/material"; -import ClassicResultListWrapper from "./result/ClassicResultListWrapper"; -import { JSONSchema7 } from "json-schema"; -import * as React from "react"; -import { - FunctionComponent, - useCallback, - useEffect, - useMemo, - useState, -} from "react"; -import { v4 as uuidv4 } from "uuid"; - -import { declarativeMappings } from "../config/lobidMappings"; -import { useSettings } from "../state/useLocalSettings"; -import { Img } from "../utils/image/Img"; -import { mapByConfig } from "../utils/mapping/mapByConfig"; -import { - DeclarativeMapping, - StrategyContext, -} from "../utils/mapping/mappingStrategies"; -import { defaultPrefix, sladb, slent } from "./formConfigs"; -import { - gndEntryFromSuggestion, - gndEntryWithMainInfo, -} from "./lobid/LobidSearchTable"; -import { findEntityByAuthorityIRI, findEntityByClass } from "../utils/discover"; -import { useGlobalCRUDOptions } from "../state/useGlobalCRUDOptions"; -import { mapAbstractDataUsingAI, mapDataUsingAI } from "../utils/ai"; -import { - useGlobalSearch, - useLoadQuery, - useModalRegistry, - useSimilarityFinderState, -} from "../state"; -import { useTranslation } from "next-i18next"; -import { searchEntityByLabel } from "../utils/discover/searchEntityByLabel"; -import { primaryFields, typeIRItoTypeName } from "../config"; -import NiceModal from "@ebay/nice-modal-react"; -import { EditEntityModal } from "./edit/EditEntityModal"; -import { PrimaryField } from "../utils/types"; -import ClassicResultListItem from "./result/ClassicResultListItem"; -import { EntityDetailElement } from "./show"; -import { - findEntityWithinLobid, - findEntityWithinLobidByIRI, -} from "../utils/lobid/findEntityWithinLobid"; -import LobidAllPropTable from "./lobid/LobidAllPropTable"; -import WikidataAllPropTable from "./wikidata/WikidataAllPropTable"; -import ClassicEntityCard from "./lobid/ClassicEntityCard"; -import { debounce } from "lodash"; -import { filterUndefOrNull } from "@slub/edb-core-utils"; -import { useQuery, useQueryClient } from "@tanstack/react-query"; -import useExtendedSchema from "../state/useExtendedSchema"; -import { BasicThingInformation } from "@slub/edb-core-types"; -import { NumberInput } from "./NumberInput"; - -// @ts-ignore -type Props = { - finderId: string; - data: any; - classIRI: string; - jsonSchema: JSONSchema7; - onEntityIRIChange?: (entityIRI: string | undefined) => void; - onMappedDataAccepted?: (data: any) => void; - onExistingEntityAccepted?: (entityIRI: string, data: any) => void; - searchOnDataPath?: string; - search?: string; - hideFooter?: boolean; -}; - -type KnowledgeSources = "kb" | "gnd" | "wikidata" | "k10plus" | "ai"; -type SelectedEntity = { - id: string; - source: KnowledgeSources; -}; -const getDefaultLabelKey = (typeIRI?: string) => { - const typeName = typeIRItoTypeName(typeIRI); - const fieldDefinitions = primaryFields[typeName] as PrimaryField | undefined; - return fieldDefinitions?.label || "title"; -}; - -export const makeDefaultMappingStrategyContext: ( - doQuery: (query) => Promise, - mappingTable?: DeclarativeMapping, -) => StrategyContext = (doQuery, mappingTable) => ({ - mappingTable, - getPrimaryIRIBySecondaryIRI: async ( - secondaryIRI: string, - authorityIRI: string, - typeIRI?: string | undefined, - ) => { - const ids = await findEntityByAuthorityIRI(secondaryIRI, typeIRI, doQuery); - if (ids.length > 0) { - console.warn("found more then one entity"); - } - return ids[0] || null; - }, - searchEntityByLabel: async ( - label: string, - typeIRI: string, - ): Promise => { - const ids = await searchEntityByLabel(label, typeIRI, doQuery); - if (ids.length > 0) { - console.warn("found more then one entity"); - } - return ids[0] || null; - }, - authorityIRI: "http://d-nb.info/gnd", - newIRI: (typeIRI: string) => { - return slent(uuidv4()).value; - }, -}); - -type FindOptions = { - limit?: number; - page?: number; - offset?: number; - pageSize?: number; -}; - -type KnowledgeBaseDescription = { - id: KnowledgeSources; - authorityIRI?: string; - label: string; - description: string; - icon: string | React.ReactNode; - find: ( - searchString: string, - typeIRI: string, - findOptions?: FindOptions, - ) => Promise; - detailRenderer?: (id: string) => React.ReactNode; - listItemRenderer?: ( - entry: any, - idx: number, - typeIRI: string, - selected: boolean, - onSelect?: (id: string, index: number) => void, - onAccept?: (id: string, entry: any) => void, - ) => React.ReactNode; -}; - -const SearchFieldWithBadges = ({ - searchString, - typeIRI, - onSearchStringChange, - selectedKnowledgeSources, - toggleKnowledgeSource, - knowledgeBases, - advancedConfigChildren, - ...rest -}: { - searchString: string; - typeIRI: string; - onSearchStringChange: (value: string) => void; - knowledgeBases: KnowledgeBaseDescription[]; - selectedKnowledgeSources: string[]; - toggleKnowledgeSource?: (source: string) => void; - advancedConfigChildren?: React.ReactNode; -} & Partial) => { - const typeName = useMemo(() => typeIRItoTypeName(typeIRI), [typeIRI]); - const { t } = useTranslation(); - return ( - - - onSearchStringChange(e.currentTarget.value)} - label={`Suche in ${selectedKnowledgeSources.join(",")} nach ${t( - typeName, - )} `} - {...rest} - /> - - - - {knowledgeBases.map(({ id, label, icon }) => { - return ( - - {icon} - - ); - })} - {advancedConfigChildren && ( - <> - - {advancedConfigChildren} - - )} - - - ); -}; - -type ListItemRendererProps = { - data: BasicThingInformation; - idx: number; - typeIRI: string; - selected: boolean; - onSelect?: (id: string, index: number) => void; - onAccept?: (id: string, data: any) => void; -}; - -const fetchBasicInformationFromGND: ( - id: string, - initialData: BasicThingInformation, -) => Promise = async ( - id: string, - initialData: BasicThingInformation, -) => { - const rawEntry = await findEntityWithinLobidByIRI(id); - const { category, secondary, avatar } = initialData; - return { - category, - avatar, - ...gndEntryWithMainInfo(rawEntry), - secondary: initialData.secondary, - }; -}; - -const GNDListItemRenderer = ({ - data: initialData, - idx, - typeIRI, - selected, - onSelect, - onAccept, -}: ListItemRendererProps) => { - const { t } = useTranslation(); - const { id } = initialData; - const queryClient = useQueryClient(); - const { data } = useQuery( - ["entityDetail", id], - async () => fetchBasicInformationFromGND(id, initialData), - { - initialData, - enabled: selected, - }, - ); - - const { resetElementIndex } = useSimilarityFinderState(); - - const handleAccept = useCallback(async () => { - const finalData = await queryClient.fetchQuery( - ["entityDetail", id], - async () => fetchBasicInformationFromGND(id, initialData), - ); - resetElementIndex(); - onAccept && onAccept(id, finalData); - }, [onAccept, id, queryClient, initialData, resetElementIndex]); - - const { acceptWishPending, setAcceptWishPending } = - useSimilarityFinderState(); - useEffect(() => { - if (selected && handleAccept && acceptWishPending) { - setAcceptWishPending(false); - handleAccept(); - } - }, [handleAccept, selected, acceptWishPending, setAcceptWishPending]); - - const { label, avatar, secondary, category } = data; - return ( - - - - - - ), - }} - popperChildren={ - - {t("accept entity")} - - } - detailView={ - <> - - {(data.allProps?.sameAs || []) - .filter(({ id }) => - id.startsWith("http://www.wikidata.org/entity/"), - ) - .map(({ id }) => ( - - ))} - - } - /> - } - /> - ); -}; - -const KBListItemRenderer = ({ - data, - idx, - typeIRI, - selected, - onSelect, - onAccept, -}: ListItemRendererProps) => { - const { id, label, avatar, secondary } = data; - - const typeName = useMemo(() => typeIRItoTypeName(typeIRI), [typeIRI]); - const loadedSchema = useExtendedSchema({ typeName, classIRI: typeIRI }); - const loadEntity = useLoadQuery(defaultPrefix, "load"); - const { resetElementIndex } = useSimilarityFinderState(); - const handleAccept = useCallback(async () => { - const finalData = (await loadEntity(id, typeIRI, loadedSchema))?.document; - if (!finalData) { - console.warn("could not load entity"); - return; - } - resetElementIndex(); - onAccept && onAccept(id, finalData); - }, [onAccept, id, loadEntity, typeIRI, loadedSchema, resetElementIndex]); - const { acceptWishPending, setAcceptWishPending } = - useSimilarityFinderState(); - useEffect(() => { - if (selected && handleAccept && acceptWishPending) { - setAcceptWishPending(false); - handleAccept(); - } - }, [handleAccept, selected, acceptWishPending, setAcceptWishPending]); - - return ( - - - - - - ), - }} - popperChildren={ - - } - /> - ); -}; -const useKnowledgeBases = () => { - const { crudOptions } = useGlobalCRUDOptions(); - const kbs: KnowledgeBaseDescription[] = useMemo( - () => [ - { - id: "kb", - label: "Lokale Datenbank", - description: "Datenbank der Ausstellung", - icon: , - find: async ( - searchString: string, - typeIRI, - findOptions?: FindOptions, - ) => { - return ( - await findEntityByClass( - searchString, - typeIRI, - crudOptions.selectFetch, - findOptions?.limit || 10, - ) - ).map( - ({ - name = "", - value, - image, - description, - }: { - name: string; - value: string; - image: string; - description: string; - }) => { - return { - label: name, - id: value, - avatar: image, - secondary: description, - }; - }, - ); - }, - listItemRenderer: ( - entry: any, - idx: number, - typeIRI: string, - selected, - onSelect, - onAccept, - ) => ( - - ), - }, - { - id: "gnd", - authorityIRI: "http://d-nb.info/gnd", - label: "GND", - description: "Gemeinsame Normdatei", - icon: ( - {"gnd - ), - find: async ( - searchString: string, - typeIRI, - findOptions?: FindOptions, - ) => { - return filterUndefOrNull( - await findEntityWithinLobid( - searchString, - typeIRItoTypeName(typeIRI), - findOptions?.limit || 10, - "json:suggest", - ), - )?.map((allProps: any) => gndEntryFromSuggestion(allProps)); - }, - listItemRenderer: ( - data: any, - idx: number, - typeIRI: string, - selected, - onSelect, - onAccept, - ) => ( - - ), - }, - ], - [crudOptions?.selectFetch], - ); - return kbs; -}; - -const SimilarityFinder: FunctionComponent = ({ - finderId, - data, - classIRI: preselectedClassIRI, - onEntityIRIChange, - onExistingEntityAccepted, - onMappedDataAccepted, - searchOnDataPath, - search, - jsonSchema, - hideFooter, -}) => { - const { openai } = useSettings(); - const [selectedKnowledgeSources, setSelectedKnowledgeSources] = useState< - KnowledgeSources[] - >(["kb", "gnd"]); - - const { - search: globalSearch, - typeName: globalTypeName, - path: globalPath, - setSearch, - } = useGlobalSearch(); - - const [limit, setLimit] = useState(20); - const handleLimitChange = useCallback( - (e: any) => setLimit(parseInt(e.target.value)), - [setLimit], - ); - const { - resetElementIndex, - elementIndex, - setElementCount, - setElementIndex, - activeFinderIds, - addActiveFinder, - removeActiveFinder, - } = useSimilarityFinderState(); - useEffect(() => { - resetElementIndex(); - addActiveFinder(finderId); - return () => { - removeActiveFinder(finderId); - }; - }, [resetElementIndex, addActiveFinder, removeActiveFinder, finderId]); - - const { t } = useTranslation(); - const handleSearchStringChange = useCallback( - (value: string) => { - setSearch(value); - }, - [setSearch], - ); - const dataPathSearch = useMemo( - () => searchOnDataPath && Resolve.data(data, searchOnDataPath), - [data, searchOnDataPath], - ); - const searchString: string | undefined = useMemo( - () => dataPathSearch || globalSearch || search || null, - [dataPathSearch, search, globalSearch], - ); - const knowledgeBases: KnowledgeBaseDescription[] = useKnowledgeBases(); - - const [searchResults, setSearchResults] = useState< - Record - >( - Object.fromEntries(knowledgeBases.map((kb) => [kb.id, []])) as Record< - KnowledgeSources, - any[] - >, - ); - - /* eslint-disable react-hooks/exhaustive-deps */ - const searchAll = useCallback( - debounce( - (searchString: string, typeIRI: string, findOptions?: FindOptions) => { - return Promise.all( - knowledgeBases.map(async (kb) => { - return { - [kb.id]: selectedKnowledgeSources.includes(kb.id) - ? await kb.find(searchString, typeIRI, findOptions) - : [], - }; - }), - ).then((results) => { - const searchResults = Object.assign({}, ...results) as Record< - KnowledgeSources, - any[] - >; - setSearchResults(searchResults); - const resultCount = Object.values(searchResults).reduce( - (acc, list = []) => acc + list.length, - 0, - ); - setElementCount(resultCount); - }); - }, - 500, - ), - [ - knowledgeBases, - selectedKnowledgeSources, - setSearchResults, - setElementCount, - ], - ); - - useEffect(() => { - if (!searchString || searchString.length < 1) return; - searchAll(searchString, preselectedClassIRI, { limit }); - }, [searchString, preselectedClassIRI, searchAll, limit]); - - const [typeName, setTypeName] = useState( - typeIRItoTypeName(preselectedClassIRI), - ); - useEffect(() => { - if (globalTypeName) setTypeName(globalTypeName); - }, [globalTypeName, setTypeName]); - const classIRI = useMemo(() => sladb(typeName).value, [typeName]); - useEffect(() => { - setTypeName(typeIRItoTypeName(preselectedClassIRI)); - }, [preselectedClassIRI, setTypeName]); - - const handleToggle = useCallback( - (id: string | undefined, source: KnowledgeSources) => { - !selectedKnowledgeSources?.includes(source) - ? setSelectedKnowledgeSources( - (before) => [...before, source] as KnowledgeSources[], - ) - : setSelectedKnowledgeSources( - (before) => before.filter((s) => s != source) as KnowledgeSources[], - ); - }, - [setSelectedKnowledgeSources, selectedKnowledgeSources], - ); - const handleMapAbstractAndDescUsingAI = useCallback( - async (id: string | undefined, entryData: any) => { - const newData = mapAbstractDataUsingAI(id, typeName, entryData, { - jsonSchema, - openai, - }); - onMappedDataAccepted && onMappedDataAccepted(newData); - }, - [typeName, onMappedDataAccepted, jsonSchema, openai], - ); - const handleMapUsingAI = useCallback( - async (id: string | undefined, entryData: any) => { - const newData = await mapDataUsingAI(id, typeName, entryData, { - jsonSchema, - openai, - }); - onMappedDataAccepted && onMappedDataAccepted(newData); - }, - [typeName, onMappedDataAccepted, jsonSchema, openai], - ); - const { crudOptions } = useGlobalCRUDOptions(); - const handleManuallyMapData = useCallback( - async ( - id: string | undefined, - entryData: any, - source: KnowledgeSources, - ) => { - if (!id || !entryData?.allProps) return; - const knowledgeBaseDescription = knowledgeBases.find( - (kb) => kb.id === source, - ); - const mappingConfig = declarativeMappings[typeName]; - if (!mappingConfig) { - console.warn(`no mapping config for ${typeName}`); - return; - } - try { - const mappingContext = makeDefaultMappingStrategyContext( - crudOptions?.selectFetch, - declarativeMappings, - ); - const existingEntry = await mappingContext.getPrimaryIRIBySecondaryIRI( - id, - knowledgeBaseDescription?.authorityIRI || "urn:local", - classIRI, - ); - const dataFromGND = await mapByConfig( - entryData.allProps, - {}, - mappingConfig, - mappingContext, - ); - if (existingEntry) { - onEntityIRIChange && onEntityIRIChange(existingEntry); - onExistingEntityAccepted && - onExistingEntityAccepted(existingEntry, dataFromGND); - return; - } - - const inject = { - "@type": classIRI, - idAuthority: { - "@id": id, - }, - lastNormUpdate: new Date().toISOString(), - }; - onMappedDataAccepted && - onMappedDataAccepted({ ...dataFromGND, ...inject }); - } catch (e) { - console.error("could not map from authority", e); - } - }, - [ - classIRI, - typeName, - onMappedDataAccepted, - onExistingEntityAccepted, - onEntityIRIChange, - crudOptions?.selectFetch, - knowledgeBases, - ], - ); - - const handleEntityChange = useCallback( - (id: string | undefined, data: any) => { - onEntityIRIChange && onEntityIRIChange(id); - onExistingEntityAccepted && onExistingEntityAccepted(id, data); - }, - [onEntityIRIChange, onExistingEntityAccepted], - ); - - const handleAccept = useCallback( - (id: string | undefined, entryData: any, source: KnowledgeSources) => { - if (source === "kb") { - handleEntityChange(id, entryData); - } else { - if (selectedKnowledgeSources?.includes("ai")) { - handleMapUsingAI(id, entryData); - } else { - handleManuallyMapData(id, entryData, source); - } - } - }, - [ - handleManuallyMapData, - handleMapUsingAI, - handleEntityChange, - selectedKnowledgeSources, - ], - ); - - const { cycleThroughElements } = useSimilarityFinderState(); - const handleKeyUp = useCallback( - (ev: React.KeyboardEvent) => { - if (ev.key === "ArrowUp" || ev.key === "ArrowDown") { - cycleThroughElements(ev.key === "ArrowDown" ? 1 : -1); - ev.preventDefault(); - } - }, - [cycleThroughElements], - ); - const [margin, setMargin] = useState(0); - const [ref, setRef] = useState(); - useEffect(() => { - if (ref) { - setMargin(ref.clientHeight); - } - }, [ref]); - const { registerModal } = useModalRegistry(); - - const showEditDialog = useCallback(() => { - const defaultLabelKey = getDefaultLabelKey(preselectedClassIRI); - const newItem = { - "@id": slent(uuidv4()).value, - "@type": preselectedClassIRI, - [defaultLabelKey]: searchString, - }; - const modalID = `edit-${newItem["@type"]}-${newItem["@id"]}`; - registerModal(modalID, EditEntityModal); - NiceModal.show(modalID, { - entityIRI: newItem["@id"], - typeIRI: newItem["@type"], - data: newItem, - disableLoad: true, - }).then(({ entityIRI, data }) => { - handleEntityChange(entityIRI, data); - }); - }, [registerModal, preselectedClassIRI, searchString, handleEntityChange]); - - /** - * in order to give each element an index across all knowledge sources we need to - * merge the results and add an index to each element - * */ - const resultsWithIndex = useMemo(() => { - let idx = 0; - const intermediate = Object.entries(searchResults).reduce( - (acc, [key, value]) => [ - ...acc, - ...value.map((entry) => { - idx++; - return { entry, idx, key }; - }), - ], - [], - ); - return Object.fromEntries( - Object.keys(searchResults).map((kb) => [ - kb, - intermediate.filter(({ key }) => key === kb), - ]), - ); - }, [searchResults]); - - const finderIsActive = useMemo( - () => - activeFinderIds.includes(finderId) && - activeFinderIds[activeFinderIds.length - 1] === finderId, - [activeFinderIds, finderId], - ); - - return ( - finderIsActive && ( -
- - - - } - /> - - - {knowledgeBases.map((kb) => { - const entries = resultsWithIndex[kb.id] || []; - return ( - - {searchString && ( - - {entries.map(({ entry, idx }) => - kb.listItemRenderer( - entry, - idx, - classIRI, - elementIndex === idx, - () => setElementIndex(idx), - (id, data) => handleAccept(id, data, kb.id), - ), - )} - - )} - - ); - })} - - - - - - - -
- ) - ); -}; - -export default SimilarityFinder; diff --git a/apps/exhibition-live/components/form/deep-graph/DeepGraphToJSONShowcase.stories.tsx b/apps/exhibition-live/components/form/deep-graph/DeepGraphToJSONShowcase.stories.tsx index 2c7f3ad5..7dabbf06 100644 --- a/apps/exhibition-live/components/form/deep-graph/DeepGraphToJSONShowcase.stories.tsx +++ b/apps/exhibition-live/components/form/deep-graph/DeepGraphToJSONShowcase.stories.tsx @@ -2,7 +2,7 @@ import DeepGraphToJSONShowcase from "./DeepGraphToJSONShowcase"; import { Meta, StoryObj } from "@storybook/react"; export default { - title: "form/exhibition/DeepGraphToJSONShowcase", + title: "architecture/graph-data/DeepGraphToJSONShowcase", component: DeepGraphToJSONShowcase, } as Meta; diff --git a/apps/exhibition-live/components/form/deep-graph/DeepGraphToJSONShowcase.tsx b/apps/exhibition-live/components/form/deep-graph/DeepGraphToJSONShowcase.tsx index 1a71d796..cb386335 100644 --- a/apps/exhibition-live/components/form/deep-graph/DeepGraphToJSONShowcase.tsx +++ b/apps/exhibition-live/components/form/deep-graph/DeepGraphToJSONShowcase.tsx @@ -8,9 +8,11 @@ import dsExt from "rdf-dataset-ext"; import React, { FunctionComponent, useEffect, useState } from "react"; import { JsonView } from "react-json-view-lite"; import stringToStream from "string-to-stream"; -import { WalkerOptions } from "@slub/edb-graph-traversal"; +import { + traverseGraphExtractBySchema, + WalkerOptions, +} from "@slub/edb-graph-traversal"; -import { jsonSchemaGraphInfuser } from "../../utils/graph/jsonSchemaGraphInfuser"; import { addressSchema } from "../../../fixtures/schema"; // @ts-ignore import tbbt from "tbbt-ld/dist/tbbt.nq"; @@ -70,7 +72,7 @@ const DeepGraphToJSONShowcase: FunctionComponent = ({ useEffect(() => { if (dataset) { - const resultJSON = jsonSchemaGraphInfuser( + const resultJSON = traverseGraphExtractBySchema( baseIRI, entityIRI, dataset as Dataset, diff --git a/apps/exhibition-live/components/form/edit/EditEntityModal.tsx b/apps/exhibition-live/components/form/edit/EditEntityModal.tsx index 682e7670..385a1d1f 100644 --- a/apps/exhibition-live/components/form/edit/EditEntityModal.tsx +++ b/apps/exhibition-live/components/form/edit/EditEntityModal.tsx @@ -1,55 +1,57 @@ import NiceModal, { useModal } from "@ebay/nice-modal-react"; -import { useTypeIRIFromEntity } from "../../state"; -import { useCallback, useMemo, useState } from "react"; -import { primaryFieldExtracts, typeIRItoTypeName } from "../../config"; -import useExtendedSchema from "../../state/useExtendedSchema"; -import { useCRUDWithQueryClient } from "../../state/useCRUDWithQueryClient"; -import { defaultJsonldContext, defaultPrefix } from "../formConfigs"; -import { useTranslation } from "next-i18next"; -import { PrimaryFieldResults } from "../../utils/types"; +import { useAdbContext, useTypeIRIFromEntity } from "@slub/edb-state-hooks"; +import { useCallback, useEffect, useMemo, useState } from "react"; import { - applyToEachField, - extractFieldIfString, -} from "../../utils/mapping/simpleFieldExtractor"; + useCRUDWithQueryClient, + useExtendedSchema, +} from "@slub/edb-state-hooks"; +import { useTranslation } from "next-i18next"; import { Button, Stack } from "@mui/material"; import { JSONSchema7 } from "json-schema"; -import { uischemata } from "../uischemaForType"; -import { uischemas } from "../uischemas"; -import { cleanJSONLD } from "../../utils/crud"; -import GenericModal from "../GenericModal"; -import { SemanticJsonFormNoOps } from "../SemanticJsonFormNoOps"; -import MuiEditDialog from "../../renderer/MuiEditDialog"; import { useSnackbar } from "notistack"; +import { useFormDataStore } from "@slub/edb-state-hooks"; +import { PrimaryFieldResults } from "@slub/edb-core-types"; +import { cleanJSONLD } from "@slub/sparql-schema"; +import { EditEntityModalProps } from "@slub/edb-global-types"; +import { MuiEditDialog } from "@slub/edb-basic-components"; +import { applyToEachField, extractFieldIfString } from "@slub/edb-data-mapping"; -type EntityDetailModalProps = { - typeIRI: string | undefined; - entityIRI: string; - data: any; - disableLoad?: boolean; -}; export const EditEntityModal = NiceModal.create( ({ typeIRI, entityIRI, data: defaultData, disableLoad, - }: EntityDetailModalProps) => { + }: EditEntityModalProps) => { + const { + jsonLDConfig, + typeIRIToTypeName, + queryBuildOptions: { primaryFieldExtracts }, + uischemata, + components: { SemanticJsonForm }, + } = useAdbContext(); const modal = useModal(); const typeIRIs = useTypeIRIFromEntity(entityIRI); - const classIRI: string | undefined = typeIRI || typeIRIs?.[0]; - const typeName = useMemo(() => typeIRItoTypeName(classIRI), [classIRI]); - const loadedSchema = useExtendedSchema({ typeName, classIRI }); - const { loadQuery, saveMutation } = useCRUDWithQueryClient( + const classIRI: string | undefined = useMemo( + () => typeIRI || typeIRIs?.[0], + [typeIRI, typeIRIs], + ); + const typeName = useMemo( + () => typeIRIToTypeName(classIRI), + [classIRI, typeIRIToTypeName], + ); + const loadedSchema = useExtendedSchema({ typeName }); + const { loadQuery, saveMutation } = useCRUDWithQueryClient({ entityIRI, - classIRI, - loadedSchema, - { + typeIRI: classIRI, + schema: loadedSchema, + queryOptions: { enabled: !disableLoad, refetchOnWindowFocus: true, initialData: defaultData, }, - "show", - ); + loadQueryKey: "show", + }); const { t } = useTranslation(); const [firstTimeSaved, setFirstTimeSaved] = useState(false); const [isStale, setIsStale] = useState(false); @@ -63,13 +65,17 @@ export const EditEntityModal = NiceModal.create( description: null, image: null, }; - }, [typeName, data]); + }, [typeName, data, primaryFieldExtracts]); - const [formData, setFormData] = useState(data); - const uischema = useMemo( - () => uischemata[typeName] || (uischemas as any)[typeName], - [typeName], - ); + const { formData, setFormData } = useFormDataStore({ + entityIRI, + typeIRI, + }); + + useEffect(() => { + setFormData(data); + }, [data, setFormData]); + const uischema = useMemo(() => uischemata?.[typeName], [typeName]); const { enqueueSnackbar } = useSnackbar(); const handleSaveSuccess = useCallback(() => { @@ -99,8 +105,8 @@ export const EditEntityModal = NiceModal.create( const handleAccept = useCallback(() => { const acceptCallback = async () => { let cleanedData = await cleanJSONLD(formData, loadedSchema, { - jsonldContext: defaultJsonldContext, - defaultPrefix, + jsonldContext: jsonLDConfig.jsonldContext, + defaultPrefix: jsonLDConfig.defaultPrefix, keepContext: true, }); modal.resolve({ @@ -109,14 +115,8 @@ export const EditEntityModal = NiceModal.create( }); modal.remove(); }; - if (isStale) { - return NiceModal.show(GenericModal, { - type: "save before proceed", - }).then(() => handleSave(acceptCallback)); - } else { - return acceptCallback(); - } - }, [formData, loadedSchema, handleSave, modal, isStale]); + return handleSave(acceptCallback); + }, [formData, loadedSchema, handleSave, modal, jsonLDConfig]); const handleSaveAndAccept = useCallback(async () => { //await handleSave(handleAccept); @@ -128,7 +128,7 @@ export const EditEntityModal = NiceModal.create( setFormData(data); setIsStale(true); }, - [setIsStale], + [setIsStale, setFormData], ); return ( @@ -147,7 +147,7 @@ export const EditEntityModal = NiceModal.create( } > - GenJSONLDSemanticPropertiesFunction = - (baseIRI: string, entityBaseIRI: string) => (modelName: string) => ({ - "@type": { - const: `${baseIRI}${modelName.replace(/Stub$/, "")}`, - type: "string", - }, - "@id": { - title: entityBaseIRI, - type: "string", - }, - idAuthority: { - title: "Autorität", - type: "object", - properties: { - "@id": { - title: "IRI", - type: "string", - }, - }, - }, - }); - -export default makeGenSlubJSONLDSemanticProperties( - sladb[""].value, - slent[""].value, -); diff --git a/apps/exhibition-live/components/form/gnd/GNDAutocompleteInput.stories.tsx b/apps/exhibition-live/components/form/gnd/GNDAutocompleteInput.stories.tsx deleted file mode 100644 index 0f5b3dd3..00000000 --- a/apps/exhibition-live/components/form/gnd/GNDAutocompleteInput.stories.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import React from "react"; - -import GNDAutocompleteInput from "./GNDAutocompleteInput"; - -export default { - title: "form/gnd/GNDAutoCompleteInput", - component: GNDAutocompleteInput, -}; - -export const GNDAutocompleteInputDefault = () => ; diff --git a/apps/exhibition-live/components/form/gnd/GNDAutocompleteInput.tsx b/apps/exhibition-live/components/form/gnd/GNDAutocompleteInput.tsx deleted file mode 100644 index 3ed54934..00000000 --- a/apps/exhibition-live/components/form/gnd/GNDAutocompleteInput.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import React, { - FunctionComponent, - useCallback, - useMemo, - useState, -} from "react"; - -import findPersonWithinGND from "../../utils/gnd/findpersonWithinGND"; -import { - AutocompleteSuggestion, - DebouncedAutocomplete, -} from "../DebouncedAutoComplete"; - -interface OwnProps { - selected?: AutocompleteSuggestion | null; - onSelectionChange?: (selection: AutocompleteSuggestion | null) => void; - typeOf?: string; -} - -type Props = OwnProps; - -const buildLabelFromSuggestion: ( - suggestion: AutocompleteSuggestion, -) => string = ({ value, label }) => `${label}, GND: ${value}`; - -const GNDAutocompleteInput: FunctionComponent = ({ - typeOf, - selected, - onSelectionChange, - typeOf: classType, -}) => { - const [_selected, setSelected] = useState( - null, - ); - - const __selected = useMemo( - () => selected || _selected, - [selected, _selected], - ); - - const handleChange = useCallback( - (_e: Event, item: AutocompleteSuggestion | null) => { - const __onSelectionChange = onSelectionChange || setSelected; - __onSelectionChange(item); - }, - [onSelectionChange, setSelected], - ); - - return ( - - searchString - ? (await findPersonWithinGND(searchString, 50, classType)).map( - ({ gndid, literal }) => ({ - label: literal, - value: gndid, - }), - ) - : [] - } - placeholder={`Suche innerhalb der GND (${typeOf})`} - getOptionLabel={buildLabelFromSuggestion} - onChange={(_event: any, item: AutocompleteSuggestion | null) => { - onSelectionChange && onSelectionChange(item); - }} - /> - ); -}; - -export default GNDAutocompleteInput; diff --git a/apps/exhibition-live/components/form/jsonforms/index.ts b/apps/exhibition-live/components/form/jsonforms/index.ts index cdbd4f17..71c1bb87 100644 --- a/apps/exhibition-live/components/form/jsonforms/index.ts +++ b/apps/exhibition-live/components/form/jsonforms/index.ts @@ -1,5 +1,13 @@ import { JsonSchema, UISchemaElement } from "@jsonforms/core"; +/** + * Convert a JSON Schema to a list of UI Schema elements + * this is very usefull if you either do not have a specific UI Schema + * or if you want to generate a UI Schema from a JSON Schema and "fill the gaps" + * of elements that are not defined in the UI Schema + * @param jsonschema + * @param subpath + */ export const jsonSchema2UISchemaElements: ( jsonschema: JsonSchema, subpath?: string, diff --git a/apps/exhibition-live/components/form/k10plus/K10PlusSearchTable.tsx b/apps/exhibition-live/components/form/k10plus/K10PlusSearchTable.tsx deleted file mode 100644 index 811fe63f..00000000 --- a/apps/exhibition-live/components/form/k10plus/K10PlusSearchTable.tsx +++ /dev/null @@ -1,332 +0,0 @@ -import { - Button, - Container, - Link, - List, - styled, - Table, - TableBody, - TableCell, - TableContainer, - TableRow, - Tooltip, - tooltipClasses, - TooltipProps, -} from "@mui/material"; -import datasetFactory from "@rdfjs/dataset"; -import { BlankNode, NamedNode } from "@rdfjs/types"; -import { dcterms, foaf, geo, rdfs, skos } from "@tpluscode/rdf-ns-builders"; -import clownface from "clownface"; -import React, { - FunctionComponent, - useCallback, - useEffect, - useMemo, - useState, -} from "react"; - -import { useLocalHistory } from "../../state"; -import { useSettings } from "../../state/useLocalSettings"; -import { findEntityWithinK10Plus } from "../../utils/k10plus/findEntityWithinK10Plus"; -import { RecordElement } from "../../utils/k10plus/searchRetrieveResponse-types"; -import ClassicEntityCard from "../lobid/ClassicEntityCard"; -import ClassicResultListItem from "../result/ClassicResultListItem"; -import { fabio, geonames, radatana } from "./marc2rdfMappingDeclaration"; -import { kxp, mapDatafieldToQuads } from "./marcxml2rdf"; -import { - NodePropertyTree, - nodeToPropertyTree, -} from "@slub/edb-graph-traversal"; -import { useTranslation } from "next-i18next"; - -type Props = { - searchString: string; - typeName?: string; - onSelect?: (id: string | undefined) => void; - onAcceptItem?: (id: string | undefined, data: any) => void; -}; - -type KXPEntry = { - id: string | number; - properties: NodePropertyTree; -}; - -const marcRecord2RDF: (record: RecordElement) => KXPEntry = (record) => { - //const mappedControlfields = record.recordData.record.controlfield.map(ds => mapControlfield(ds)) - const id = record.recordData.record.controlfield.filter( - (cf) => cf["@_tag"] === "001", - )[0]["#text"]; - const subjectNode = kxp("record/" + String(id)); - const extractedKnowledge = record.recordData.record.datafield.flatMap((ds) => - mapDatafieldToQuads(subjectNode, ds), - ); - const dataset = datasetFactory.dataset(extractedKnowledge); - const tbbt = clownface({ dataset }); - const properties = nodeToPropertyTree(subjectNode, tbbt); - return { - id, - properties, - }; -}; - -export const findFirstInProps = ( - props: NodePropertyTree, - ...predicates: NamedNode[] -): string | undefined => { - for (const predicate of predicates) { - const value = props[predicate.value]; - if (value?.[0]) { - return value[0].value; - } - } - return undefined; -}; -const K10PlusSearchTable: FunctionComponent = ({ - searchString, - typeName = "Person", - onSelect, - onAcceptItem, -}) => { - const { t } = useTranslation(); - const [resultTable, setResultTable] = useState(); - const { history, pushHistory, popHistory } = useLocalHistory(); - const [selectedId, setSelectedId] = useState(); - const [selectedEntry, setSelectedEntry] = useState(); - const { externalAuthority } = useSettings(); - const k10PlusEndpointURL = - externalAuthority.kxp?.endpoint || "https://sru.bsz-bw.de/swbtest", - k10PlusBaseURL = externalAuthority.kxp?.baseURL || "https://kxp.k10plus.de", - k10PlusDetailURL = `${k10PlusBaseURL}/DB=2.1/PPNSET?PPN=`; - - const fetchData = useCallback(async () => { - if (!searchString || searchString.length < 1) return; - - const entities = await findEntityWithinK10Plus( - searchString, - typeName, - k10PlusEndpointURL, - 10, - externalAuthority.kxp?.recordSchema, - ); - if (!entities?.searchRetrieveResponse) return; - const mappedFields = entities.searchRetrieveResponse.records?.record?.map( - (record) => marcRecord2RDF(record), - ); - setResultTable(mappedFields); - }, [ - searchString, - typeName, - k10PlusEndpointURL, - externalAuthority.kxp?.recordSchema, - setResultTable, - ]); - - const handleSelect = useCallback( - async (id: string | undefined, push: boolean = true) => { - setSelectedId(id); - push && pushHistory(id); - const cachedEntry = - id && resultTable?.find((entry) => String(entry.id) === id); - if (!cachedEntry) { - setSelectedEntry(undefined); - onSelect && onSelect(undefined); - return; - } - setSelectedEntry(cachedEntry); - onSelect && onSelect(id); - }, - [setSelectedId, resultTable, setSelectedEntry, onSelect, pushHistory], - ); - - useEffect(() => { - fetchData(); - }, [searchString, typeName, fetchData]); - - const handleAccept = useCallback( - (id: string | undefined) => { - onAcceptItem && onAcceptItem(id, selectedEntry); - }, - [onAcceptItem, selectedEntry], - ); - - return ( - <> - {selectedEntry && ( - <> - handleSelect(popHistory(), false)} - cardActionChildren={ - - } - id={selectedId} - detailView={} - /> - - )} - - {resultTable?.map((entry, idx) => ( - handleSelect(id)} - label={ - entry.properties[dcterms.title.value]?.[0]?.value || - String(entry.id) - } - secondary={findFirstInProps( - entry.properties, - fabio.hasSubtitle, - dcterms.description, - dcterms.abstract, - )} - altAvatar={String(idx + 1)} - /> - ))} - - - ); -}; - -const LabledLink = ({ - uri, - label, - onClick, -}: { - uri: string; - label?: string; - onClick?: () => void; -}) => { - const urlSuffix = useMemo( - () => - uri.substring( - (uri.includes("#") ? uri.lastIndexOf("#") : uri.lastIndexOf("/")) + 1 ?? - 0, - uri.length, - ), - [uri], - ); - return ( - - {label || urlSuffix} - - ); -}; -const LightTooltip = styled(({ className, ...props }: TooltipProps) => ( - -))(({ theme }) => ({ - [`& .${tooltipClasses.tooltip}`]: { - backgroundColor: theme.palette.common.white, - color: "rgba(0, 0, 0, 0.87)", - boxShadow: theme.shadows[1], - fontSize: 11, - }, -})); -const LabeledBNode = ({ - bnode, - properties, -}: { - bnode: BlankNode; - properties: NodePropertyTree; -}) => { - const label = useMemo( - () => - findFirstInProps( - properties, - foaf.name, - dcterms.title, - skos.prefLabel, - rdfs.label, - radatana.catalogueName, - geonames("name"), - ), - [properties], - ); - return ( - - - - } - > - - - ); -}; -const KXPAllPropTable = ({ entry }: { entry: KXPEntry }) => { - return ( - - - - {Object.entries(entry.properties).map(([key, value]) => { - return ( - - - - - - {(Array.isArray(value) && - value.map((v, index) => { - const comma = index < value.length - 1 ? "," : ""; - if (v.termType === "Literal") { - return ( - - {v.value} - {comma}{" "} - - ); - } - if (v.termType === "NamedNode") { - return ( - - - {comma} - - ); - } - if (v.termType === "BlankNode") { - return ( - - - {comma} - - ); - } - })) || - typeof value === "string" || - typeof value === "number" || - (typeof value === "boolean" && value)} - - - ); - })} - -
-
- ); -}; - -export default K10PlusSearchTable; diff --git a/apps/exhibition-live/components/form/lobid/LobidAllPropsTable.stories.tsx b/apps/exhibition-live/components/form/lobid/LobidAllPropsTable.stories.tsx index 8cf513ae..8ff71bfb 100644 --- a/apps/exhibition-live/components/form/lobid/LobidAllPropsTable.stories.tsx +++ b/apps/exhibition-live/components/form/lobid/LobidAllPropsTable.stories.tsx @@ -1,9 +1,8 @@ import React from "react"; - -import LobidAllPropTable from "./LobidAllPropTable"; +import { LobidAllPropTable } from "@slub/edb-advanced-components"; export default { - title: "presentation/lobid/LobidAllPropsTable", + title: "ui/view/LobidAllPropsTable", component: LobidAllPropTable, }; diff --git a/apps/exhibition-live/components/form/lobid/LobidAutocomplete.stories.tsx b/apps/exhibition-live/components/form/lobid/LobidAutocomplete.stories.tsx index f2ef0c83..7df0fe10 100644 --- a/apps/exhibition-live/components/form/lobid/LobidAutocomplete.stories.tsx +++ b/apps/exhibition-live/components/form/lobid/LobidAutocomplete.stories.tsx @@ -3,7 +3,7 @@ import React from "react"; import LobidAutocompleteSearch from "./LobidAutocompleteSearch"; export default { - title: "form/lobid/LobidAutocomplete", + title: "ui/form/LobidAutocomplete", component: LobidAutocompleteSearch, }; diff --git a/apps/exhibition-live/components/form/lobid/LobidAutocompleteSearch.tsx b/apps/exhibition-live/components/form/lobid/LobidAutocompleteSearch.tsx index 950cd359..1b072067 100644 --- a/apps/exhibition-live/components/form/lobid/LobidAutocompleteSearch.tsx +++ b/apps/exhibition-live/components/form/lobid/LobidAutocompleteSearch.tsx @@ -5,11 +5,10 @@ import React, { useState, } from "react"; -import { findEntityWithinLobid } from "../../utils/lobid/findEntityWithinLobid"; -import { - AutocompleteSuggestion, - DebouncedAutocomplete, -} from "../DebouncedAutoComplete"; +import { DebouncedAutocomplete } from "@slub/edb-advanced-components"; +import { AutocompleteSuggestion } from "@slub/edb-core-types"; +import { findEntityWithinLobid } from "@slub/edb-authorities"; +import { lobidTypemap } from "@slub/exhibition-schema"; interface OwnProps { selected?: AutocompleteSuggestion | null; @@ -54,6 +53,7 @@ const LobidAutocompleteSearch: FunctionComponent = ({ await findEntityWithinLobid( searchString, typeName || "Person", + lobidTypemap, 50, ) )?.member?.map( diff --git a/apps/exhibition-live/components/form/lobid/LobidSearchTable.stories.tsx b/apps/exhibition-live/components/form/lobid/LobidSearchTable.stories.tsx index b0546f0e..441f73bd 100644 --- a/apps/exhibition-live/components/form/lobid/LobidSearchTable.stories.tsx +++ b/apps/exhibition-live/components/form/lobid/LobidSearchTable.stories.tsx @@ -1,10 +1,10 @@ import React from "react"; import LobidSearchTable from "./LobidSearchTable"; -import { sladb } from "../formConfigs"; +import { sladb } from "../../config/formConfigs"; export default { - title: "form/lobid/LobidSearchTable", + title: "ui/form/LobidSearchTable", component: LobidSearchTable, }; diff --git a/apps/exhibition-live/components/form/lobid/LobidSearchTable.tsx b/apps/exhibition-live/components/form/lobid/LobidSearchTable.tsx index e1efdbbe..852e6194 100644 --- a/apps/exhibition-live/components/form/lobid/LobidSearchTable.tsx +++ b/apps/exhibition-live/components/form/lobid/LobidSearchTable.tsx @@ -6,28 +6,30 @@ import React, { useState, } from "react"; +import { filterUndefOrNull } from "@slub/edb-ui-utils"; +import { useQuery } from "@slub/edb-state-hooks"; +import { typeIRItoTypeName } from "../../config"; +import Ajv from "ajv"; +import { useTranslation } from "next-i18next"; import { - findEntityWithinLobid, - findEntityWithinLobidByIRI, -} from "../../utils/lobid/findEntityWithinLobid"; -import ClassicResultListItem from "../result/ClassicResultListItem"; -import ClassicEntityCard from "./ClassicEntityCard"; -import LobidAllPropTable from "./LobidAllPropTable"; -import WikidataAllPropTable from "../wikidata/WikidataAllPropTable"; -import { + BasicThingInformation, PrimaryFieldExtract, PrimaryFieldExtractDeclaration, -} from "../../utils/types"; -import { filterUndefOrNull } from "../../utils/core"; +} from "@slub/edb-core-types"; import { - applyToEachField, - extractFieldIfString, -} from "../../utils/mapping/simpleFieldExtractor"; -import { useQuery } from "@tanstack/react-query"; -import { typeIRItoTypeName } from "../../config"; -import Ajv from "ajv"; -import { useTranslation } from "next-i18next"; -import { BasicThingInformation } from "@slub/edb-core-types"; + ClassicEntityCard, + ClassicResultListItem, +} from "@slub/edb-basic-components"; +import { + LobidAllPropTable, + WikidataAllPropTable, +} from "@slub/edb-advanced-components"; +import { + findEntityWithinLobid, + findEntityWithinLobidByIRI, +} from "@slub/edb-authorities"; +import { applyToEachField, extractFieldIfString } from "@slub/edb-data-mapping"; +import { lobidTypemap } from "@slub/exhibition-schema"; type Props = { searchString: string; @@ -44,6 +46,11 @@ type LobIDEntry = { const nullOnEmpty = (arr: any[]) => (arr.length > 0 ? arr : null); +const defaultGndPrimaryFieldExtract: PrimaryFieldExtract = { + label: "preferredName", + image: (entry: any) => entry.depiction?.[0]?.thumbnail, +}; + const gndPrimaryFields: PrimaryFieldExtractDeclaration = { DifferentiatedPerson: { label: "preferredName", @@ -75,7 +82,7 @@ const getFirstMatchingFieldDeclaration = ( fieldDeclaration: PrimaryFieldExtractDeclaration, ): PrimaryFieldExtract | null => { const key = Object.keys(fieldDeclaration).find((key) => type.includes(key)); - return key ? fieldDeclaration[key] : null; + return key ? fieldDeclaration[key] : defaultGndPrimaryFieldExtract; }; const defaultPrimaryFields: PrimaryFieldExtract = { @@ -174,6 +181,7 @@ const LobidSearchTable: FunctionComponent = ({ await findEntityWithinLobid( searchString, typeIRItoTypeName(typeIRI), + lobidTypemap, 10, ) )?.member?.map((allProps: any) => gndEntryWithMainInfo(allProps)), @@ -236,6 +244,7 @@ const LobidSearchTable: FunctionComponent = ({ size="small" color="primary" variant="contained" + className="accept-button" disabled={!onAcceptItem || !selectedEntry} onClick={() => onAcceptItem && onAcceptItem(id, selectedEntry) diff --git a/apps/exhibition-live/components/form/show/EntityDetailCard.stories.tsx b/apps/exhibition-live/components/form/show/EntityDetailCard.stories.tsx index 1add0285..b7617484 100644 --- a/apps/exhibition-live/components/form/show/EntityDetailCard.stories.tsx +++ b/apps/exhibition-live/components/form/show/EntityDetailCard.stories.tsx @@ -1,9 +1,8 @@ -import { EntityDetailCard } from "./"; -import { Box } from "@mui/material"; import { Meta, StoryObj } from "@storybook/react"; +import { EntityDetailCard } from "@slub/edb-advanced-components"; export default { - title: "presentation/kb/EntityDetailCard", + title: "ui/view/EntityDetailCard", component: EntityDetailCard, } as Meta; @@ -32,10 +31,12 @@ const exampleOne = { sourceCorporation: { idAuthority: {}, }, - fromDateDisplay: "05.04.2014", - toDateDisplay: "13.07.2014", - startDate: {}, - endDate: {}, + startDate: { + dateValue: 20140405, + }, + endDate: { + dateValue: 20140713, + }, exhibitionType: { "@id": "http://ontologies.slub-dresden.de/exhibition/entity/EventType#s-1", diff --git a/apps/exhibition-live/components/form/show/EntityDetailCard.tsx b/apps/exhibition-live/components/form/show/EntityDetailCard.tsx deleted file mode 100644 index 69372c3f..00000000 --- a/apps/exhibition-live/components/form/show/EntityDetailCard.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import React, { FunctionComponent, useCallback } from "react"; -import { JsonView } from "react-json-view-lite"; -import { PrimaryFieldResults } from "../../utils/types"; -import { - Button, - Card, - CardActionArea, - CardActions, - CardContent, - CardMedia, - Typography, -} from "@mui/material"; -import { useTranslation } from "next-i18next"; -import LobidAllPropTable from "../lobid/LobidAllPropTable"; -import { useModifiedRouter } from "../../basic"; -import { encodeIRI } from "../../utils/core"; - -import { typeIRItoTypeName } from "../../config"; -import { useSettings } from "../../state/useLocalSettings"; -import NiceModal from "@ebay/nice-modal-react"; -import { EditEntityModal } from "../edit/EditEntityModal"; -import { useModalRegistry } from "../../state"; -import { EntityDetailCardProps } from "./EntityDetailCardProps"; -import { StylizedDetailCard } from "./StylizedDetailCard"; - -export const EntityDetailCard: FunctionComponent = ({ - typeIRI, - entityIRI, - cardInfo, - data, - cardActionChildren, - readonly, - inlineEditing, - onEditClicked, - tableProps = {}, -}) => { - const { t } = useTranslation(); - - const router = useModifiedRouter(); - const { registerModal } = useModalRegistry(); - const editEntry = useCallback(() => { - const typeName = typeIRItoTypeName(typeIRI); - if (inlineEditing === true) { - const modalID = `edit-${typeIRI}-${entityIRI}`; - registerModal(modalID, EditEntityModal); - NiceModal.show(modalID, { - entityIRI: entityIRI, - typeIRI: typeIRI, - data, - disableLoad: true, - }); - } else { - router.push(`/create/${typeName}?encID=${encodeIRI(entityIRI)}`); - } - onEditClicked && onEditClicked(); - }, [ - router, - typeIRI, - entityIRI, - inlineEditing, - registerModal, - data, - onEditClicked, - ]); - - const { - features: { enableDebug }, - } = useSettings(); - - return ( - <> - {cardInfo.image && cardInfo.description ? ( - - {inlineEditing ? t("edit inline") : t("edit")} - - ) - } - /> - ) : ( - - - {cardInfo.image && ( - - )} - - - {cardInfo.label} - - - {cardInfo.description} - - - - {cardActionChildren !== null && ( - - {typeof cardActionChildren !== "undefined" ? ( - cardActionChildren - ) : ( - <> - {!readonly && ( - - )} - - )} - - )} - - )} - - {enableDebug && ( - <> - lvl < 3} /> - lvl < 3} /> - - )} - - ); -}; diff --git a/apps/exhibition-live/components/form/show/EntityDetailCardProps.ts b/apps/exhibition-live/components/form/show/EntityDetailCardProps.ts deleted file mode 100644 index f5d05d8d..00000000 --- a/apps/exhibition-live/components/form/show/EntityDetailCardProps.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { PrimaryFieldResults } from "../../utils/types"; -import React from "react"; -import { AllPropTableProps } from "../lobid/LobidAllPropTable"; - -type OwnProps = { - typeIRI: string; - entityIRI: string; - cardInfo: PrimaryFieldResults; - cardActionChildren?: React.ReactNode; - data: any; - readonly?: boolean; - inlineEditing?: boolean; - onEditClicked?: () => void; - tableProps?: Partial; -}; - -export type EntityDetailCardProps = OwnProps; diff --git a/apps/exhibition-live/components/form/show/MarkdownContent.tsx b/apps/exhibition-live/components/form/show/MarkdownContent.tsx index 80a35998..9d8b32a1 100644 --- a/apps/exhibition-live/components/form/show/MarkdownContent.tsx +++ b/apps/exhibition-live/components/form/show/MarkdownContent.tsx @@ -2,12 +2,7 @@ import React, { useEffect } from "react"; import { useRemark } from "react-remark"; import { Container } from "@mui/material"; import rehypeDocument from "rehype-document"; -import rehypeKatex from "rehype-katex"; -import remark2rehype from "remark-rehype"; -import rehypeParse from "rehype-parse"; import rehypeStringify from "rehype-stringify"; -import rehypeMermaid from "rehype-mermaid"; -import remarkMath from "remark-math"; import rehypeVideo from "rehype-video"; export type MarkdownContentProps = { @@ -15,11 +10,10 @@ export type MarkdownContentProps = { }; const MarkdownContent = ({ mdDocument }: MarkdownContentProps) => { const [reactContent, setMarkdownSource] = useRemark({ - remarkPlugins: [remarkMath], + //remarkPlugins: [remarkMath], rehypePlugins: [ - [rehypeParse as any, { fragment: true }], + // [rehypeParse as any, { fragment: true }], rehypeDocument as any, - rehypeKatex as any, [ rehypeVideo as any, { @@ -35,7 +29,6 @@ const MarkdownContent = ({ mdDocument }: MarkdownContentProps) => { details: true, }, ], - [rehypeMermaid as any, { strategy: "img-svg" }], rehypeStringify as any, ], }); diff --git a/apps/exhibition-live/components/form/show/StylizedDetailCard.tsx b/apps/exhibition-live/components/form/show/StylizedDetailCard.tsx index 271f9e43..c911ec5f 100644 --- a/apps/exhibition-live/components/form/show/StylizedDetailCard.tsx +++ b/apps/exhibition-live/components/form/show/StylizedDetailCard.tsx @@ -1,9 +1,9 @@ import React, { useEffect, useMemo, useRef, useState } from "react"; import { Box, Fab, styled, Typography } from "@mui/material"; -import { EntityDetailCardProps } from "./EntityDetailCardProps"; import ColorThief from "color-thief-ts"; import MarkdownContent from "./MarkdownContentNoSSR"; import { ArrowLeft, ArrowRight } from "@mui/icons-material"; +import { EntityDetailCardProps } from "@slub/edb-advanced-components"; type ColorArray = [number, number, number]; @@ -232,12 +232,15 @@ export const StylizedDetailCard = ({ className="image-content animate slide delay-5" style={{ backgroundImage: `url(${cardInfo.image})` }} > - {cardInfo.label} + { + // eslint-disable-next-line @next/next/no-img-element + {cardInfo.label} + }
diff --git a/apps/exhibition-live/components/form/similarity-finder/GNDListItemRenderer.tsx b/apps/exhibition-live/components/form/similarity-finder/GNDListItemRenderer.tsx new file mode 100644 index 00000000..e5de57a9 --- /dev/null +++ b/apps/exhibition-live/components/form/similarity-finder/GNDListItemRenderer.tsx @@ -0,0 +1,122 @@ +import { useTranslation } from "next-i18next"; +import { + useQuery, + useQueryClient, + useSimilarityFinderState, +} from "@slub/edb-state-hooks"; +import { BasicThingInformation } from "@slub/edb-core-types"; +import { fetchBasicInformationFromGND } from "./fetchBasicInformationFromGND"; +import * as React from "react"; +import { useCallback, useEffect } from "react"; +import { + ClassicEntityCard, + ClassicResultListItem, +} from "@slub/edb-basic-components"; +import { Button, IconButton, Stack } from "@mui/material"; +import { Check } from "@mui/icons-material"; +import { + LobidAllPropTable, + WikidataAllPropTable, +} from "@slub/edb-advanced-components"; +import { ListItemRendererProps } from "./types"; + +export const GNDListItemRenderer = ({ + data: initialData, + idx, + typeIRI, + selected, + onSelect, + onAccept, +}: ListItemRendererProps) => { + const { t } = useTranslation(); + const { id } = initialData; + const queryClient = useQueryClient(); + const { data } = useQuery( + ["entityDetail", id], + async () => fetchBasicInformationFromGND(id, initialData), + { + initialData, + enabled: selected, + }, + ); + + const { resetElementIndex } = useSimilarityFinderState(); + + const handleAccept = useCallback(async () => { + const finalData = await queryClient.fetchQuery( + ["entityDetail", id], + async () => fetchBasicInformationFromGND(id, initialData), + ); + resetElementIndex(); + onAccept && onAccept(id, finalData); + }, [onAccept, id, queryClient, initialData, resetElementIndex]); + + const { acceptWishPending, setAcceptWishPending } = + useSimilarityFinderState(); + useEffect(() => { + if (selected && handleAccept && acceptWishPending) { + setAcceptWishPending(false); + handleAccept(); + } + }, [handleAccept, selected, acceptWishPending, setAcceptWishPending]); + + const { label, avatar, secondary, category } = data; + return ( + + + + + + ), + }} + popperChildren={ + + {t("accept entity")} + + } + detailView={ + <> + + {(data.allProps?.sameAs || []) + .filter(({ id }) => + id.startsWith("http://www.wikidata.org/entity/"), + ) + .map(({ id }) => ( + + ))} + + } + /> + } + /> + ); +}; diff --git a/apps/exhibition-live/components/form/similarity-finder/KBListItemRenderer.stories.tsx b/apps/exhibition-live/components/form/similarity-finder/KBListItemRenderer.stories.tsx new file mode 100644 index 00000000..e6c64185 --- /dev/null +++ b/apps/exhibition-live/components/form/similarity-finder/KBListItemRenderer.stories.tsx @@ -0,0 +1,40 @@ +import React from "react"; +import { Meta, StoryObj } from "@storybook/react"; +import { BasicThingInformation } from "@slub/edb-core-types"; +import { KBListItemRenderer } from "./KBListItemRenderer"; + +export default { + title: "ui/similarity-finder/KBListItemRenderer", + component: KBListItemRenderer, +} as Meta; + +type Story = StoryObj; + +const sampleData: BasicThingInformation = { + id: "example-id", + label: "Example Label", + avatar: "http://example.com/avatar.png", + secondary: "Additional Information", +}; + +export const Primary: Story = { + args: { + data: sampleData, + idx: 1, + typeIRI: "http://example.org/type", + selected: false, + }, +}; + +export const VeryLongDescription: Story = { + args: { + data: { + ...sampleData, + secondary: + "This is a very long description that should be truncated. We can continue to write a lot of text here, but it will be cut off at some point. The item should still be displayed correctly.", + }, + idx: 1, + typeIRI: "http://example.org/type", + selected: false, + }, +}; diff --git a/apps/exhibition-live/components/form/similarity-finder/KBListItemRenderer.tsx b/apps/exhibition-live/components/form/similarity-finder/KBListItemRenderer.tsx new file mode 100644 index 00000000..7ccaf394 --- /dev/null +++ b/apps/exhibition-live/components/form/similarity-finder/KBListItemRenderer.tsx @@ -0,0 +1,97 @@ +import { ListItemRendererProps } from "./types"; +import { + useAdbContext, + useCRUDWithQueryClient, + useExtendedSchema, + useSimilarityFinderState, +} from "@slub/edb-state-hooks"; +import * as React from "react"; +import { useCallback, useEffect, useMemo } from "react"; +import { ClassicResultListItem } from "@slub/edb-basic-components"; +import { IconButton, Stack } from "@mui/material"; +import { Check } from "@mui/icons-material"; +import { EntityDetailElement } from "@slub/edb-advanced-components"; + +export const KBListItemRenderer = ({ + data, + idx, + typeIRI, + selected, + onSelect, + onAccept, +}: ListItemRendererProps) => { + const { id, label, avatar, secondary } = data; + const { + jsonLDConfig: { defaultPrefix }, + typeIRIToTypeName, + } = useAdbContext(); + + const typeName = useMemo( + () => typeIRIToTypeName(typeIRI), + [typeIRI, typeIRIToTypeName], + ); + const loadedSchema = useExtendedSchema({ typeName }); + const { loadEntity } = useCRUDWithQueryClient({ + entityIRI: id, + typeIRI, + schema: loadedSchema, + queryOptions: { enabled: false }, + loadQueryKey: "load", + }); + const { resetElementIndex } = useSimilarityFinderState(); + const handleAccept = useCallback(async () => { + const finalData = (await loadEntity(id, typeIRI))?.document; + if (!finalData) { + console.warn("could not load entity"); + return; + } + resetElementIndex(); + onAccept && onAccept(id, finalData); + }, [onAccept, id, loadEntity, typeIRI, loadedSchema, resetElementIndex]); + const { acceptWishPending, setAcceptWishPending } = + useSimilarityFinderState(); + useEffect(() => { + if (selected && handleAccept && acceptWishPending) { + setAcceptWishPending(false); + handleAccept(); + } + }, [handleAccept, selected, acceptWishPending, setAcceptWishPending]); + + return ( + + + + + + ), + }} + popperChildren={ + + } + /> + ); +}; diff --git a/apps/exhibition-live/components/form/similarity-finder/MappingTestComponent.stories.tsx b/apps/exhibition-live/components/form/similarity-finder/MappingTestComponent.stories.tsx new file mode 100644 index 00000000..1c05451d --- /dev/null +++ b/apps/exhibition-live/components/form/similarity-finder/MappingTestComponent.stories.tsx @@ -0,0 +1,16 @@ +import { MappingTestComponent } from "./MappingTestComponent"; +import { Meta, StoryObj } from "@storybook/react"; + +const meta: Meta = { + title: "mapping/MappingTestComponent", + component: MappingTestComponent, +}; +export default meta; + +type Story = StoryObj; + +export const Primary: Story = { + args: { + typeName: "Location", + }, +}; diff --git a/apps/exhibition-live/components/form/similarity-finder/MappingTestComponent.tsx b/apps/exhibition-live/components/form/similarity-finder/MappingTestComponent.tsx new file mode 100644 index 00000000..d2215e08 --- /dev/null +++ b/apps/exhibition-live/components/form/similarity-finder/MappingTestComponent.tsx @@ -0,0 +1,116 @@ +import { useSimilarityFinderState } from "@slub/edb-state-hooks"; +import { SimilarityFinder } from "./SimilarityFinder"; +import { useKnowledgeBases } from "./useKnowledgeBases"; +import React, { useCallback, useMemo, useState } from "react"; +import { useDeclarativeMapper } from "./useDeclarativeMapper"; +import { Grid, Paper } from "@mui/material"; +import { exhibitionConfig } from "../../config/exhibitionAppConfig"; +import { set } from "lodash"; +import { JsonView } from "react-json-view-lite"; + +type MappingTestComponentProps = { + typeName: + | "Location" + | "Place" + | "Person" + | "Organization" + | "Event" + | "Performance" + | "Occupation" + | "Exhibition" + | "ExhibitionSeries"; +}; + +export const MappingTestComponent: React.FC = ({ + typeName, +}) => { + const knowledgeBases = useKnowledgeBases(); + const typeIRI = useMemo( + () => exhibitionConfig.typeNameToTypeIRI(typeName), + [typeName], + ); + const [selectedID, setSelectedID] = useState(null); + const [selectedAuthorityIRI, setSelectedAuthorityIRI] = useState< + string | null + >(null); + const [mappedData, setMappedData] = useState(null); + const [originalData, setOriginalData] = useState(null); + const [loading, setLoading] = useState(false); + + const { mapData } = useDeclarativeMapper(); + + const handleEntitySelected = useCallback( + async (id: string, authorityIRI: string) => { + setLoading(true); + setSelectedID(id); + setSelectedAuthorityIRI(authorityIRI); + const knowledgeBase = knowledgeBases.find( + (kb) => kb.authorityIRI === authorityIRI, + ); + if (!knowledgeBase?.getEntity) { + console.error(`No getEntity method found for ${authorityIRI}`); + console.log({ knowledgeBase }); + return; + } + if (id.startsWith("https://d-nb.info")) { + id = id.replace("https://d-nb.info/gnd/", ""); + } + const entryData = await knowledgeBase.getEntity(id, typeName); + setOriginalData(entryData); + const mappedData = await mapData( + id, + typeIRI, + { allProps: entryData }, + authorityIRI, + ); + console.log({ mappedData, entryData }); + setMappedData(mappedData); + setLoading(false); + }, + [knowledgeBases, setMappedData, setOriginalData, typeIRI, typeName], + ); + + return ( + + + console.log(`Entity IRI Changed: ${iri}`)} + onExistingEntityAccepted={(iri, data) => + console.log(`Existing Entity Accepted: ${iri}, Data: ${data}`) + } + onMappedDataAccepted={(data) => + console.log(`Mapped Data Accepted: ${data}`) + } + search="Dresden" + jsonSchema={{}} + hideFooter={false} + knowledgeSources={["wikidata"]} + onSelectedEntityChange={handleEntitySelected} + /> + + + + {/* Content for the second column */} +

Original Data

+ lvl < 3} + /> +
+
+ + + {/* Content for the third column */} +

Mapped Data

+ lvl < 3} + /> +
+
+
+ ); +}; diff --git a/apps/exhibition-live/components/form/similarity-finder/SearchFieldWithBadges.stories.tsx b/apps/exhibition-live/components/form/similarity-finder/SearchFieldWithBadges.stories.tsx new file mode 100644 index 00000000..6c2c8321 --- /dev/null +++ b/apps/exhibition-live/components/form/similarity-finder/SearchFieldWithBadges.stories.tsx @@ -0,0 +1,44 @@ +import React from "react"; +import { Meta, StoryObj } from "@storybook/react"; +import { SearchFieldWithBadges } from "./SearchFieldWithBadges"; +import { KnowledgeBaseDescription } from "./types"; + +export default { + title: "ui/similarity-finder/SearchFieldWithBadges", + component: SearchFieldWithBadges, +} as Meta; + +type Story = StoryObj; + +const knowledgeBases: KnowledgeBaseDescription[] = [ + { + id: "kb", + label: "Knowledge Base Blue", + icon: ( +
+ ), + description: "This is a description of the knowledge base blue", + find: (searchString) => Promise.resolve([]), + }, + { + id: "wikidata", + label: "Knowledge Base Green", + icon: ( +
+ ), + description: "This is a description of the knowledge base green", + find: (searchString) => Promise.resolve([]), + }, +]; + +export const Primary: Story = { + args: { + searchString: "Sample search", + typeIRI: "http://example.com/type", + onSearchStringChange: (value: string) => + console.log(`Search Changed: ${value}`), + knowledgeBases: knowledgeBases, + selectedKnowledgeSources: ["kb"], + advancedConfigChildren:
Advanced Config
, + }, +}; diff --git a/apps/exhibition-live/components/form/similarity-finder/SearchFieldWithBadges.tsx b/apps/exhibition-live/components/form/similarity-finder/SearchFieldWithBadges.tsx new file mode 100644 index 00000000..7f92e5fe --- /dev/null +++ b/apps/exhibition-live/components/form/similarity-finder/SearchFieldWithBadges.tsx @@ -0,0 +1,100 @@ +import { KnowledgeBaseDescription } from "./types"; +import * as React from "react"; +import { useMemo } from "react"; +import { + Badge, + Box, + Divider, + Grid, + TextField, + TextFieldProps, +} from "@mui/material"; +import { useAdbContext } from "@slub/edb-state-hooks"; +import { useTranslation } from "next-i18next"; + +export const SearchFieldWithBadges = ({ + searchString, + typeIRI, + onSearchStringChange, + selectedKnowledgeSources, + toggleKnowledgeSource, + knowledgeBases, + advancedConfigChildren, + ...rest +}: { + searchString: string; + typeIRI: string; + onSearchStringChange: (value: string) => void; + knowledgeBases: KnowledgeBaseDescription[]; + selectedKnowledgeSources: string[]; + toggleKnowledgeSource?: (source: string) => void; + advancedConfigChildren?: React.ReactNode; +} & Partial) => { + const { typeIRIToTypeName } = useAdbContext(); + const typeName = useMemo( + () => typeIRIToTypeName(typeIRI), + [typeIRI, typeIRIToTypeName], + ); + const { t } = useTranslation(); + return ( + + + onSearchStringChange(e.currentTarget.value)} + label={`Suche in ${selectedKnowledgeSources.join(",")} nach ${t( + typeName, + )} `} + {...rest} + /> + + + + {knowledgeBases.map(({ id, label, icon }) => { + return ( + + {icon} + + ); + })} + {advancedConfigChildren && ( + <> + + {advancedConfigChildren} + + )} + + + ); +}; diff --git a/apps/exhibition-live/components/form/similarity-finder/SimilarityFinder.stories.tsx b/apps/exhibition-live/components/form/similarity-finder/SimilarityFinder.stories.tsx new file mode 100644 index 00000000..9ce94654 --- /dev/null +++ b/apps/exhibition-live/components/form/similarity-finder/SimilarityFinder.stories.tsx @@ -0,0 +1,27 @@ +import { Meta, StoryObj } from "@storybook/react"; +import { SimilarityFinder } from "./SimilarityFinder"; + +export default { + title: "ui/similarity-finder/SimilarityFinder", + component: SimilarityFinder, +} as Meta; + +type Story = StoryObj; + +export const Primary: Story = { + args: { + finderId: "finder-1", + data: {}, + classIRI: "http://ontologies.slub-dresden.de/exhibition#Person", + onEntityIRIChange: (iri) => console.log(`Entity IRI Changed: ${iri}`), + onExistingEntityAccepted: (iri, data) => + console.log(`Existing Entity Accepted: ${iri}, Data: ${data}`), + onMappedDataAccepted: (data) => + console.log(`Mapped Data Accepted: ${data}`), + search: "Otto Dix", + jsonSchema: {}, + hideFooter: false, + additionalKnowledgeSources: ["wikidata"], + searchOnDataPath: "path.to.search", + }, +}; diff --git a/apps/exhibition-live/components/form/similarity-finder/SimilarityFinder.tsx b/apps/exhibition-live/components/form/similarity-finder/SimilarityFinder.tsx new file mode 100644 index 00000000..b54229c4 --- /dev/null +++ b/apps/exhibition-live/components/form/similarity-finder/SimilarityFinder.tsx @@ -0,0 +1,504 @@ +import { Resolve } from "@jsonforms/core"; +import { NoteAdd } from "@mui/icons-material"; +import { Button, CircularProgress, Grid, Hidden, List } from "@mui/material"; +import * as React from "react"; +import { + FunctionComponent, + useCallback, + useEffect, + useMemo, + useState, +} from "react"; + +import { + useAdbContext, + useDataStore, + useGlobalCRUDOptions, + useGlobalSearch, + useModalRegistry, + useSimilarityFinderState, +} from "@slub/edb-state-hooks"; +import { useTranslation } from "next-i18next"; +import NiceModal from "@ebay/nice-modal-react"; +import { debounce, uniq } from "lodash"; +import { PrimaryField } from "@slub/edb-core-types"; +import { NumberInput } from "../NumberInput"; +import { ClassicResultListWrapper } from "@slub/edb-basic-components"; +import { + KnowledgeSources, + SimilarityFinderProps, +} from "@slub/edb-global-types"; +import { FindOptions, KnowledgeBaseDescription } from "./types"; +import { SearchFieldWithBadges } from "./SearchFieldWithBadges"; +import { useKnowledgeBases } from "./useKnowledgeBases"; +import { useDeclarativeMapper } from "./useDeclarativeMapper"; + +const performSearch = ( + searchString: string, + typeIRI: string, + typeName: string, + findOptions: FindOptions, + knowledgeBases: KnowledgeBaseDescription[], + setSearchResults: (searchResults: Record) => void, + setElementCount: (resultCount: number) => void, +) => { + return Promise.all( + knowledgeBases.map(async (kb) => { + return { + [kb.id]: await kb.find(searchString, typeIRI, typeName, findOptions), + }; + }), + ).then((results) => { + if (!results) return; + const searchResults = Object.assign({}, ...results) as Record< + KnowledgeSources, + any[] + >; + setSearchResults(searchResults); + const resultCount = Object.values(searchResults).reduce( + (acc, list = []) => acc + list.length, + 0, + ); + setElementCount(resultCount); + }); +}; + +export const SimilarityFinder: FunctionComponent = ({ + finderId, + data, + classIRI: preselectedClassIRI, + onEntityIRIChange, + onExistingEntityAccepted, + onMappedDataAccepted, + onSelectedEntityChange, + searchOnDataPath, + search, + jsonSchema, + hideFooter, + knowledgeSources, + additionalKnowledgeSources, +}) => { + const { + schema, + queryBuildOptions, + normDataMapping, + createEntityIRI, + typeNameToTypeIRI, + typeIRIToTypeName, + jsonLDConfig: { defaultPrefix }, + components: { EditEntityModal }, + } = useAdbContext(); + const [typeName, setTypeName] = useState( + typeIRIToTypeName(preselectedClassIRI), + ); + const allKnowledgeBases: KnowledgeBaseDescription[] = useKnowledgeBases(); + const selectedKnowledgeSources = useMemo(() => { + const preselectedKnowledgeSources = + knowledgeSources || + allKnowledgeBases + .filter((kb) => normDataMapping[kb.authorityIRI]?.mapping?.[typeName]) + .map((kb) => kb.id); + + return uniq([ + "kb", + ...preselectedKnowledgeSources, + ...(additionalKnowledgeSources || []), + ]); + }, [ + additionalKnowledgeSources, + knowledgeSources, + normDataMapping, + allKnowledgeBases, + typeName, + ]); + + const { prefixes, primaryFields } = queryBuildOptions; + const { + search: globalSearch, + typeName: globalTypeName, + path: globalPath, + setSearch, + } = useGlobalSearch(); + + const [limit, setLimit] = useState(20); + const handleLimitChange = useCallback( + (e: any) => setLimit(parseInt(e.target.value)), + [setLimit], + ); + const { + resetElementIndex, + elementIndex, + setElementCount, + setElementIndex, + activeFinderIds, + addActiveFinder, + removeActiveFinder, + } = useSimilarityFinderState(); + useEffect(() => { + resetElementIndex(); + addActiveFinder(finderId); + return () => { + removeActiveFinder(finderId); + }; + }, [resetElementIndex, addActiveFinder, removeActiveFinder, finderId]); + + const { t } = useTranslation(); + const handleSearchStringChange = useCallback( + (value: string) => { + setSearch(value); + }, + [setSearch], + ); + const dataPathSearch = useMemo( + () => searchOnDataPath && Resolve.data(data, searchOnDataPath), + [data, searchOnDataPath], + ); + const searchString: string | undefined = useMemo( + () => dataPathSearch || globalSearch || search || null, + [dataPathSearch, search, globalSearch], + ); + const knowledgeBases = useMemo( + () => + allKnowledgeBases.filter(({ id }) => + selectedKnowledgeSources.includes(id), + ), + [allKnowledgeBases, selectedKnowledgeSources], + ); + + const [searchResults, setSearchResults] = useState< + Record + >( + Object.fromEntries(knowledgeBases.map((kb) => [kb.id, []])) as Record< + KnowledgeSources, + any[] + >, + ); + + const debouncedSearch = React.useRef(debounce(performSearch, 500)).current; + + const doSearch = useCallback( + (search: string) => + debouncedSearch( + search, + preselectedClassIRI, + typeIRIToTypeName(preselectedClassIRI), + { limit }, + knowledgeBases, + setSearchResults, + setElementCount, + ), + [ + knowledgeBases, + preselectedClassIRI, + limit, + knowledgeBases, + setSearchResults, + setElementCount, + debouncedSearch, + typeIRIToTypeName, + ], + ); + + //const typeName = useMemo(() => typeIRIToTypeName(preselectedClassIRI), [typeIRIToTypeName, preselectedClassIRI]) + const [mappingInProgress, setMappingInProgress] = useState(false); + + useEffect(() => { + debouncedSearch.cancel(); + if (!searchString || searchString.length < 1) return; + doSearch(searchString); + }, [searchString, doSearch, debouncedSearch]); + + useEffect(() => { + if (globalTypeName) setTypeName(globalTypeName); + }, [globalTypeName, setTypeName]); + useEffect(() => { + setTypeName(typeIRIToTypeName(preselectedClassIRI)); + }, [preselectedClassIRI, setTypeName, typeIRIToTypeName]); + const classIRI = useMemo( + () => typeNameToTypeIRI(typeName), + [typeName, typeNameToTypeIRI], + ); + + const { crudOptions } = useGlobalCRUDOptions(); + const { dataStore, ready } = useDataStore({ + schema, + crudOptionsPartial: crudOptions, + typeNameToTypeIRI, + queryBuildOptions, + }); + const { mapData } = useDeclarativeMapper(); + const handleManuallyMapData = useCallback( + async ( + id: string | undefined, + entryData: any, + source: KnowledgeSources, + ) => { + console.log("manually map data", id, entryData, source); + setMappingInProgress(true); + if (!id || !entryData?.allProps) return; + try { + const knowledgeBase = knowledgeBases.find((kb) => kb.id === source); + const finalData = await mapData( + id, + classIRI, + entryData, + knowledgeBase.authorityIRI, + ); + console.log("finalData", finalData); + onMappedDataAccepted && onMappedDataAccepted(finalData); + } catch (e) { + console.error("could not map from authority", e); + } + setMappingInProgress(false); + }, + [ + mapData, + classIRI, + onMappedDataAccepted, + knowledgeBases, + setMappingInProgress, + ], + ); + + const handleEntityChange = useCallback( + (id: string | undefined, data: any) => { + onEntityIRIChange && onEntityIRIChange(id); + onExistingEntityAccepted && onExistingEntityAccepted(id, data); + }, + [onEntityIRIChange, onExistingEntityAccepted], + ); + + const handleAccept = useCallback( + (id: string | undefined, entryData: any, source: KnowledgeSources) => { + if (source === "kb") { + handleEntityChange(id, entryData); + } else { + handleManuallyMapData(id, entryData, source); + } + }, + [handleManuallyMapData, handleEntityChange], + ); + + const { cycleThroughElements } = useSimilarityFinderState(); + const handleKeyUp = useCallback( + (ev: React.KeyboardEvent) => { + if (ev.key === "ArrowUp" || ev.key === "ArrowDown") { + cycleThroughElements(ev.key === "ArrowDown" ? 1 : -1); + ev.preventDefault(); + } + }, + [cycleThroughElements], + ); + const [margin, setMargin] = useState(0); + const [ref, setRef] = useState(); + useEffect(() => { + if (ref) { + setMargin(ref.clientHeight); + } + }, [ref]); + const { registerModal, modalRegistry } = useModalRegistry(NiceModal); + + const getDefaultLabelKey = useCallback( + (typeIRI?: string) => { + const fieldDefinitions = primaryFields[typeName] as + | PrimaryField + | undefined; + return fieldDefinitions?.label || "title"; + }, + [primaryFields, typeName], + ); + + const showEditDialog = useCallback(() => { + const defaultLabelKey = getDefaultLabelKey(preselectedClassIRI); + const newItem = { + "@id": createEntityIRI(preselectedClassIRI), + "@type": preselectedClassIRI, + [defaultLabelKey]: searchString, + }; + const modalID = `edit-${newItem["@type"]}-${newItem["@id"]}`; + registerModal(modalID, EditEntityModal); + NiceModal.show(modalID, { + entityIRI: newItem["@id"], + typeIRI: newItem["@type"], + data: newItem, + disableLoad: true, + }).then(({ entityIRI, data }: { entityIRI: string; data: any }) => { + handleEntityChange(entityIRI, data); + }); + }, [ + registerModal, + preselectedClassIRI, + searchString, + handleEntityChange, + typeIRIToTypeName, + createEntityIRI, + getDefaultLabelKey, + EditEntityModal, + ]); + + /** + * in order to give each element an index across all knowledge sources we need to + * merge the results and add an index to each element + * */ + const resultsWithIndex = useMemo(() => { + let idx = 0; + const intermediate = Object.entries(searchResults).reduce( + (acc, [key, value]) => [ + ...acc, + ...value.map((entry) => { + idx++; + return { entry, idx, key }; + }), + ], + [], + ); + return Object.fromEntries( + Object.keys(searchResults).map((kb) => [ + kb, + intermediate.filter(({ key }) => key === kb), + ]), + ); + }, [searchResults]); + + const finderIsActive = useMemo( + () => + activeFinderIds.includes(finderId) && + activeFinderIds[activeFinderIds.length - 1] === finderId, + [activeFinderIds, finderId], + ); + + const handleSelectEntity = useCallback( + (id: string, index: number, kb: KnowledgeBaseDescription) => { + setElementIndex(index); + if (onSelectedEntityChange) { + onSelectedEntityChange(id, kb.authorityIRI); + } + }, + [setElementIndex, onSelectedEntityChange], + ); + + return ( + finderIsActive && ( +
+ {mappingInProgress ? ( +
+ +
+ ) : null} +
+ + + + } + /> + + + {knowledgeBases.map((kb) => { + const entries = resultsWithIndex[kb.id] || []; + return ( + + {searchString && ( + + {entries.map(({ entry, idx }) => + kb.listItemRenderer( + entry, + idx, + classIRI, + elementIndex === idx, + (id, index) => handleSelectEntity(id, index, kb), + (id, data) => handleAccept(id, data, kb.id), + ), + )} + + )} + + ); + })} + {Array.from(modalRegistry) + .map((modal) => modal) + .join(",")} + + + + + + + +
+
+ ) + ); +}; diff --git a/apps/exhibition-live/components/form/similarity-finder/fetchBasicInformationFromGND.ts b/apps/exhibition-live/components/form/similarity-finder/fetchBasicInformationFromGND.ts new file mode 100644 index 00000000..12ce2c4e --- /dev/null +++ b/apps/exhibition-live/components/form/similarity-finder/fetchBasicInformationFromGND.ts @@ -0,0 +1,21 @@ +import { BasicThingInformation } from "@slub/edb-core-types"; +import { findEntityWithinLobidByIRI } from "@slub/edb-authorities"; +import { gndEntryWithMainInfo } from "../lobid/LobidSearchTable"; + +export const fetchBasicInformationFromGND: ( + id: string, + initialData: BasicThingInformation, +) => Promise = async ( + id: string, + initialData: BasicThingInformation, +) => { + const rawEntry = await findEntityWithinLobidByIRI(id); + const { category, secondary, avatar } = initialData; + const entry = gndEntryWithMainInfo(rawEntry); + return { + category, + avatar, + ...entry, + secondary: initialData.secondary, + }; +}; diff --git a/apps/exhibition-live/components/form/similarity-finder/index.ts b/apps/exhibition-live/components/form/similarity-finder/index.ts new file mode 100644 index 00000000..85eb811b --- /dev/null +++ b/apps/exhibition-live/components/form/similarity-finder/index.ts @@ -0,0 +1,6 @@ +export * from "./types"; +export * from "./SimilarityFinder"; +export * from "./GNDListItemRenderer"; +export * from "./fetchBasicInformationFromGND"; +export { KBListItemRenderer } from "./KBListItemRenderer"; +export { useKnowledgeBases } from "./useKnowledgeBases"; diff --git a/apps/exhibition-live/components/form/similarity-finder/provider/GND.tsx b/apps/exhibition-live/components/form/similarity-finder/provider/GND.tsx new file mode 100644 index 00000000..d507f7aa --- /dev/null +++ b/apps/exhibition-live/components/form/similarity-finder/provider/GND.tsx @@ -0,0 +1,42 @@ +import { KnowledgeBaseDescription } from "../types"; +import { Img } from "../../../basic"; +import { findEntityWithinLobid } from "@slub/edb-authorities"; +import { filterUndefOrNull } from "@slub/edb-core-utils"; +import { gndEntryFromSuggestion } from "../../lobid/LobidSearchTable"; +import { GNDListItemRenderer } from "../GNDListItemRenderer"; +import { lobidTypemap } from "@slub/exhibition-schema"; + +export const GND: KnowledgeBaseDescription = { + id: "gnd", + authorityIRI: "http://d-nb.info/gnd", + label: "GND", + description: "Gemeinsame Normdatei", + icon: ( + {"gnd + ), + find: async (searchString, typeIRI, typeName, findOptions) => { + return filterUndefOrNull( + await findEntityWithinLobid( + searchString, + typeName, + lobidTypemap, + findOptions?.limit || 10, + "json:suggest", + ), + )?.map((allProps: any) => gndEntryFromSuggestion(allProps)); + }, + getEntity: async (id, typeIRI) => { + return await findEntityWithinLobid(id, typeIRI, lobidTypemap, 1, "json"); + }, + listItemRenderer: (data, idx, typeIRI, selected, onSelect, onAccept) => ( + + ), +}; diff --git a/apps/exhibition-live/components/form/similarity-finder/provider/K10Plus.tsx b/apps/exhibition-live/components/form/similarity-finder/provider/K10Plus.tsx new file mode 100644 index 00000000..5b233fce --- /dev/null +++ b/apps/exhibition-live/components/form/similarity-finder/provider/K10Plus.tsx @@ -0,0 +1,52 @@ +import { KnowledgeBaseDescription } from "../types"; +import { Img } from "../../../basic"; +import { findEntityWithinK10Plus } from "@slub/edb-kxp-utils"; +import { ClassicResultListItem } from "@slub/edb-basic-components"; +import { dcterms } from "@tpluscode/rdf-ns-builders"; +import { findFirstInProps, RootNode } from "@slub/edb-graph-traversal"; +import { fabio } from "@slub/edb-marc-to-rdf"; + +export const K10Plus: KnowledgeBaseDescription = { + id: "k10plus", + label: "K10plus", + description: "K10plus", + icon: ( + {"gnd + ), + find: async (searchString, typeIRI, typeName, findOptions) => { + const test = await findEntityWithinK10Plus( + searchString, + typeName, + "http://sru.k10plus.de/gvk", + findOptions?.limit || 10, + "marcxml", + ); + return test || []; + }, + listItemRenderer: (entry, idx, typeIRI, selected, onSelect, onAccept) => { + const data = entry as RootNode; + return ( + onSelect(id, index)} + label={ + data.properties[dcterms.title.value]?.[0]?.value || String(data.id) + } + secondary={findFirstInProps( + data.properties, + fabio.hasSubtitle, + dcterms.description, + dcterms.abstract, + )} + altAvatar={String(idx + 1)} + /> + ); + }, +}; diff --git a/apps/exhibition-live/components/form/similarity-finder/provider/KBMainDatabase.tsx b/apps/exhibition-live/components/form/similarity-finder/provider/KBMainDatabase.tsx new file mode 100644 index 00000000..34b2417e --- /dev/null +++ b/apps/exhibition-live/components/form/similarity-finder/provider/KBMainDatabase.tsx @@ -0,0 +1,51 @@ +import { KnowledgeBaseDescription } from "../types"; +import { Storage as KnowledgebaseIcon } from "@mui/icons-material"; +import { applyToEachField, extractFieldIfString } from "@slub/edb-data-mapping"; +import { PrimaryField, PrimaryFieldDeclaration } from "@slub/edb-core-types"; +import { KBListItemRenderer } from "../KBListItemRenderer"; +import { AbstractDatastore } from "@slub/edb-global-types"; +import { typeIRItoTypeName } from "../../../config"; + +export const KBMainDatabase: ( + dataStore: AbstractDatastore, + primaryFields: PrimaryFieldDeclaration, +) => KnowledgeBaseDescription = (dataStore, primaryFields) => ({ + id: "kb", + label: "Lokale Datenbank", + description: "Datenbank der Ausstellung", + icon: , + find: async (searchString, typeIRI, typeName, findOptions) => { + const res = await dataStore.findDocuments( + typeName, + { search: searchString }, + findOptions?.limit, + ); + return res.map((doc) => { + const { label, image, description } = applyToEachField( + doc, + primaryFields[typeName] as PrimaryField, + extractFieldIfString, + ); + return { + label, + id: doc["@id"], + avatar: image, + secondary: description, + }; + }); + }, + getEntity(id, typeIRI) { + return dataStore.loadDocument(typeIRItoTypeName(typeIRI), id); + }, + listItemRenderer: (entry, idx, typeIRI, selected, onSelect, onAccept) => ( + + ), +}); diff --git a/apps/exhibition-live/components/form/similarity-finder/provider/Wikidata.tsx b/apps/exhibition-live/components/form/similarity-finder/provider/Wikidata.tsx new file mode 100644 index 00000000..a027dffb --- /dev/null +++ b/apps/exhibition-live/components/form/similarity-finder/provider/Wikidata.tsx @@ -0,0 +1,99 @@ +import { KnowledgeBaseDescription } from "../types"; +import { Img } from "../../../basic"; +import { + CommonPropertyValues, + getCommonPropsFromWikidata, + getEntityFromWikidataByIRI, + WikidataRESTResult, +} from "@slub/edb-ui-utils"; +import { filterUndefOrNull } from "@slub/edb-core-utils"; +import { ClassicResultListItem } from "@slub/edb-basic-components"; +import { IconButton, Stack } from "@mui/material"; +import { Check } from "@mui/icons-material"; +import { WikidataAllPropTable } from "@slub/edb-advanced-components"; +import { wikidataTypeMap } from "@slub/exhibition-schema"; +import { use } from "chai"; +import { useCallback } from "react"; + +const stripWikidataPrefixFromProps = (allProps: CommonPropertyValues) => { + return Object.fromEntries( + Object.entries(allProps).map(([key, value]) => { + const strippedKey = key.replace("http://www.wikidata.org/entity/", ""); + return [strippedKey, value]; + }), + ) as CommonPropertyValues; +}; + +export const Wikidata: KnowledgeBaseDescription = { + id: "wikidata", + label: "Wikidata", + authorityIRI: "http://www.wikidata.org", + description: "Wikidata", + icon: ( + {"wikidata + ), + find: async (searchString, typeIRI, typeName, findOptions) => { + const type = wikidataTypeMap[typeName]; + const reconciliationURL = new URL( + "https://wikidata.reconci.link/en/suggest/entity", + ); + reconciliationURL.search = new URLSearchParams({ + prefix: searchString, + ...(type ? { type: Array.isArray(type) ? type.join(",") : type } : {}), + }).toString(); + const response = await fetch(reconciliationURL.toString(), { + method: "GET", + }); + const data = await response.json(); + return data.result.map((item: any) => ({ + id: item.id, + key: item.id, + title: item.name, + description: item.description, + thumbnail: { url: "" }, // Assuming no thumbnail is provided + })); + }, + getEntity: async (id) => + await getEntityFromWikidataByIRI(id, { rank: "preferred" }), + listItemRenderer: (entry, idx, typeIRI, selected, onSelect, onAccept) => { + const data = entry as WikidataRESTResult["pages"][0]; + const wikidataEntityIRI = `http://www.wikidata.org/entity/${data.key}`; + const handleAccept = () => { + getEntityFromWikidataByIRI(wikidataEntityIRI, { rank: "preferred" }).then( + (res) => { + const allProps = res; // stripWikidataPrefixFromProps(allProps_); + return onAccept(wikidataEntityIRI, { ...data, allProps }); + }, + ); + }; + return ( + onSelect(id, index)} + label={data.title} + secondary={data.description} + avatar={data.thumbnail?.url} + altAvatar={String(idx + 1)} + selected={selected} + onEnter={handleAccept} + listItemProps={{ + secondaryAction: ( + + + + + + ), + }} + popperChildren={} + /> + ); + }, +}; diff --git a/apps/exhibition-live/components/form/similarity-finder/provider/index.ts b/apps/exhibition-live/components/form/similarity-finder/provider/index.ts new file mode 100644 index 00000000..55c256b4 --- /dev/null +++ b/apps/exhibition-live/components/form/similarity-finder/provider/index.ts @@ -0,0 +1,4 @@ +export { KBMainDatabase } from "./KBMainDatabase"; +export { Wikidata } from "./Wikidata"; +export { GND } from "./GND"; +export { K10Plus } from "./K10Plus"; diff --git a/apps/exhibition-live/components/form/similarity-finder/types.ts b/apps/exhibition-live/components/form/similarity-finder/types.ts new file mode 100644 index 00000000..abe16f7f --- /dev/null +++ b/apps/exhibition-live/components/form/similarity-finder/types.ts @@ -0,0 +1,46 @@ +import { KnowledgeSources } from "@slub/edb-global-types"; +import * as React from "react"; +import { BasicThingInformation } from "@slub/edb-core-types"; + +export type SelectedEntity = { + id: string; + source: KnowledgeSources; +}; +export type FindOptions = { + limit?: number; + page?: number; + offset?: number; + pageSize?: number; +}; + +export type ListItemRendererProps = { + data: BasicThingInformation; + idx: number; + typeIRI: string; + selected: boolean; + onSelect?: (id: string, index: number) => void; + onAccept?: (id: string, data: any) => void; +}; +export type KnowledgeBaseDescription = { + id: KnowledgeSources; + authorityIRI?: string; + label: string; + description: string; + icon: string | React.ReactNode; + find: ( + searchString: string, + typeIRI: string, + typeName: string, + findOptions?: FindOptions, + ) => Promise; + getEntity?: (id: string, typeIRI?: string) => Promise; + detailRenderer?: (id: string) => React.ReactNode; + listItemRenderer?: ( + entry: any, + idx: number, + typeIRI: string, + selected: boolean, + onSelect?: (id: string, index: number) => void, + onAccept?: (id: string, entry: any) => void, + ) => React.ReactNode; +}; diff --git a/apps/exhibition-live/components/form/similarity-finder/useDeclarativeMapper.ts b/apps/exhibition-live/components/form/similarity-finder/useDeclarativeMapper.ts new file mode 100644 index 00000000..7421c027 --- /dev/null +++ b/apps/exhibition-live/components/form/similarity-finder/useDeclarativeMapper.ts @@ -0,0 +1,169 @@ +import NiceModal from "@ebay/nice-modal-react"; +import { NormDataMapping, PrimaryField } from "@slub/edb-core-types"; +import { DeclarativeFlatMapping, mapByConfig } from "@slub/edb-data-mapping"; +import { KnowledgeSources } from "@slub/edb-global-types"; +import { + useSimilarityFinderState, + useModalRegistry, + useGlobalCRUDOptions, + useDataStore, + useAdbContext, +} from "@slub/edb-state-hooks"; +import { makeDefaultMappingStrategyContext } from "@slub/edb-ui-utils"; +import { primaryFields } from "@slub/exhibition-schema"; +import prefixes from "@zazuko/rdf-vocabularies/prefixes"; +import { useCallback, useState, useEffect } from "react"; + +const getMappingConfig = ( + normDataMapping: Record, + authorityIRI: string, + typeName: string, +) => { + const declarativeMapping = normDataMapping[authorityIRI]; + if (!declarativeMapping) { + throw new Error(`no mapping declaration config for ${authorityIRI}`); + } + const mappingConfig = declarativeMapping.mapping[typeName]; + if (!mappingConfig) { + throw new Error(`no mapping config for ${typeName}`); + } + + return mappingConfig; +}; + +export const useDeclarativeMapper = () => { + const { + schema, + typeNameToTypeIRI, + typeIRIToTypeName, + queryBuildOptions, + createEntityIRI, + normDataMapping, + jsonLDConfig, + } = useAdbContext(); + const { crudOptions } = useGlobalCRUDOptions(); + const { dataStore, ready } = useDataStore({ + schema, + crudOptionsPartial: crudOptions, + typeNameToTypeIRI, + queryBuildOptions, + }); + + const mapData = useCallback( + async ( + id: string | undefined, + classIRI: string, + entryData: any, + authorityIRI: string, + limit: number = 1, + ) => { + if (!id || !entryData?.allProps) return; + try { + const defaultMappingContext = makeDefaultMappingStrategyContext( + crudOptions?.selectFetch, + { + defaultPrefix: jsonLDConfig.defaultPrefix, + prefixes, + }, + createEntityIRI, + typeIRIToTypeName, + primaryFields, + normDataMapping, + ); + + const mappingConfig = getMappingConfig( + normDataMapping, + authorityIRI, + typeIRIToTypeName(classIRI), + ); + + const mappingContext = { + ...defaultMappingContext, + onNewDocument: async ({ _draft, ...doc }: any) => { + const entityIRI = doc["@id"]; + const typeName_ = typeIRIToTypeName(doc["@type"]); + //return dataStore.createDocument(typeName_, doc); + try { + const newDoc = await dataStore.upsertDocument( + typeName_, + entityIRI, + doc, + ); + return newDoc; + } catch (e) { + console.error("could not create document", e); + } + return null; + }, + getPrimaryIRIBySecondaryIRI: async ( + secondaryIRI: string, + authorityIRI: string, + typeIRI: string, + ) => { + const typeName_ = typeIRIToTypeName(typeIRI); + const ids = await dataStore.findDocumentsByAuthorityIRI( + typeName_, + secondaryIRI, + authorityIRI, + limit, + ); + if (ids.length > 0) { + console.warn("found more then one entity"); + } + return ids[0] || null; + }, + searchEntityByLabel: async (label: string, typeIRI: string) => { + const typeName_ = typeIRIToTypeName(typeIRI); + const ids = await dataStore.findDocumentsByLabel( + typeName_, + label, + limit, + ); + if (ids.length > 0) { + console.warn("found more then one entity"); + } + return ids[0] || null; + }, + }; + const existingEntry = await mappingContext.getPrimaryIRIBySecondaryIRI( + id, + authorityIRI, + classIRI, + ); + const dataFromAuthority = await mapByConfig( + entryData.allProps, + {}, + mappingConfig, + mappingContext, + ); + + const inject = { + "@type": classIRI, + idAuthority: { + authority: authorityIRI, + id: id, + }, + lastNormUpdate: new Date().toISOString(), + }; + const finalData = { ...dataFromAuthority, ...inject }; + console.log("finalData", finalData); + return finalData; + } catch (e) { + console.error("could not map from authority", e); + } + }, + [ + typeIRIToTypeName, + dataStore.upsertDocument, + crudOptions?.selectFetch, + createEntityIRI, + jsonLDConfig.defaultPrefix, + normDataMapping, + prefixes, + primaryFields, + normDataMapping, + ], + ); + + return { mapData }; +}; diff --git a/apps/exhibition-live/components/form/similarity-finder/useKnowledgeBases.tsx b/apps/exhibition-live/components/form/similarity-finder/useKnowledgeBases.tsx new file mode 100644 index 00000000..6c9a9c64 --- /dev/null +++ b/apps/exhibition-live/components/form/similarity-finder/useKnowledgeBases.tsx @@ -0,0 +1,30 @@ +import { + useAdbContext, + useDataStore, + useGlobalCRUDOptions, +} from "@slub/edb-state-hooks"; +import { useMemo } from "react"; +import { KBMainDatabase, Wikidata, GND, K10Plus } from "./provider"; +import { KnowledgeBaseDescription } from "./types"; + +export const useKnowledgeBases = () => { + const { schema, typeNameToTypeIRI, queryBuildOptions, jsonLDConfig } = + useAdbContext(); + const { crudOptions } = useGlobalCRUDOptions(); + const { dataStore, ready } = useDataStore({ + schema, + crudOptionsPartial: crudOptions, + typeNameToTypeIRI, + queryBuildOptions, + }); + const kbs: KnowledgeBaseDescription[] = useMemo( + () => [ + KBMainDatabase(dataStore, queryBuildOptions.primaryFields), + Wikidata, + GND, + K10Plus, + ], + [queryBuildOptions, jsonLDConfig, dataStore, ready], + ); + return kbs; +}; diff --git a/apps/exhibition-live/components/form/uischema/Exhibition.uischema.json b/apps/exhibition-live/components/form/uischema/Exhibition.uischema.json deleted file mode 100644 index 5b541dea..00000000 --- a/apps/exhibition-live/components/form/uischema/Exhibition.uischema.json +++ /dev/null @@ -1,265 +0,0 @@ -{ - "type": "Categorization", - "elements": [ - { - "type": "Category", - "label": "Allgemeine Daten der Ausstellung", - "elements": [ - { - "type": "HorizontalLayout", - "elements": [ - { - "type": "Control", - "label": "Titel der Ausstellung", - "scope": "#/properties/title", - "options": { - "focus": true - } - }, - { - "type": "Control", - "label": "Untertitel", - "scope": "#/properties/subtitle" - }, - { - "type": "Control", - "label": "Originaltitel", - "scope": "#/properties/originalTitle" - } - ] - }, - { - "type": "Control", - "label": "Kurzbeschreibung", - "scope": "#/properties/description", - "options": { - "multi": true - } - }, - { - "type": "HorizontalLayout", - "elements": [ - { - "type": "Control", - "label": "Ausstellungsart", - "scope": "#/properties/exhibitionType" - }, - { - "type": "Control", - "label": "Kategorie", - "scope": "#/properties/exhibitionCategory" - } - ] - }, - { - "type": "Control", - "label": "Genre", - "scope": "#/properties/exhibitionGenre", - "options": { - "chips": true - } - }, - { - "type": "Control", - "label": "Ausstellungsserie", - "scope": "#/properties/exhibitionSeries" - }, - { - "type": "Control", - "label": "Schlagworte", - "scope": "#/properties/tags", - "options": { - "chips": true - } - }, - { - "type": "Control", - "label": "Bild", - "scope": "#/properties/image" - }, - { - "type": "HorizontalLayout", - "elements": [ - { - "type": "Control", - "scope": "#/properties/@id" - }, - { - "type": "Control", - "scope": "#/properties/@type" - } - ] - } - ] - }, - { - "type": "Category", - "label": "Verortung", - "elements": [ - { - "type": "Control", - "label": "Ausstellungsstätten (Institutionen und Räume)", - "scope": "#/properties/places", - "options": { - "detail": "GENERATED" - } - }, - { - "type": "Control", - "label": "Ausstellungsorte (Städte und Länder)", - "scope": "#/properties/locations", - "options": { - "detail": "GENERATED" - } - } - ] - }, - { - "type": "Category", - "label": "Zeitlicher Rahmen", - "elements": [ - { - "type": "VerticalLayout", - "elements": [ - { - "type": "HorizontalLayout", - "elements": [ - { - "type": "Group", - "elements": [ - { - "type": "Control", - "label": "Beginn", - "scope": "#/properties/startDate" - } - ] - }, - { - "type": "Group", - "elements": [ - { - "type": "Control", - "label": "Ende", - "scope": "#/properties/endDate" - } - ] - } - ] - }, - { - "type": "HorizontalLayout", - "elements": [ - { - "type": "Control", - "scope": "#/properties/vernissage", - "label": "Vernissage" - }, - { - "type": "Control", - "scope": "#/properties/midissage", - "label": "Midissage" - }, - { - "type": "Control", - "scope": "#/properties/finissage", - "label": "Finissage" - } - ] - } - ] - } - ] - }, - { - "type": "Category", - "label": "Personen und Institutionen", - "elements": [ - { - "type": "Control", - "label": "Künstler", - "scope": "#/properties/involvedPersons", - "options": { - "imagePath": "person.image", - "elementLabelTemplate": "{{=it.person?.name || ''}} ({{=it.role?.title || ''}})", - "elementDetailItemPath": "person", - "detail": "GENERATED", - "isReifiedStatement": true, - "autoFocusOnValid": true - } - }, - { - "type": "Control", - "label": "Institutionen", - "scope": "#/properties/involvedCorporations", - "options": { - "elementImagePath": "corporation.image", - "elementLabelTemplate": "{{=it.corporation?.name || ''}} ({{=it.role?.title || ''}})", - "elementDetailItemPath": "corporation", - "detail": "GENERATED", - "isReifiedStatement": true, - "autoFocusOnValid": true - } - } - ] - }, - { - "type": "Category", - "label": "Exponate", - "elements": [ - { - "type": "Control", - "label": "Exponate", - "scope": "#/properties/exponats" - } - ] - }, - { - "type": "Category", - "label": "Quellen", - "elements": [ - { - "type": "Control", - "label": "Link zur virtuellen Ausstellung", - "scope": "#/properties/exhibitionweblink" - }, - { - "type": "Control", - "label": "Ressourcen", - "scope": "#/properties/resources", - "options": { - "elementLabelProp": "title", - "detail": "GENERATED" - } - } - ] - }, - { - "type": "Category", - "label": "Daten zur Erfassung", - "elements": [ - { - "type": "HorizontalLayout", - "elements": [ - { - "type": "Control", - "label": "Veröffentlicht", - "scope": "#/properties/published" - } - ] - }, - { - "type": "Control", - "label": "Erfassungshinweise", - "scope": "#/properties/editorNote", - "options": { - "multi": true - } - } - ] - } - ], - "options": { - "variant": "stepper", - "showNavButtons": true - } -} diff --git a/apps/exhibition-live/components/form/uischema/InvolvedPerson.uischema.json b/apps/exhibition-live/components/form/uischema/InvolvedPerson.uischema.json deleted file mode 100644 index d73ec2b6..00000000 --- a/apps/exhibition-live/components/form/uischema/InvolvedPerson.uischema.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "type": "HorizontalLayout", - "elements": [ - { - "type": "Control", - "label": "Person", - "scope": "#/properties/person" - }, - { - "type": "Control", - "label": "Rolle in der Ausstellung", - "scope": "#/properties/role" - } - ] -} diff --git a/apps/exhibition-live/components/form/wikidata/Wikidata.stories.tsx b/apps/exhibition-live/components/form/wikidata/Wikidata.stories.tsx index cf4e9889..9242ee48 100644 --- a/apps/exhibition-live/components/form/wikidata/Wikidata.stories.tsx +++ b/apps/exhibition-live/components/form/wikidata/Wikidata.stories.tsx @@ -1,11 +1,11 @@ import React from "react"; +import { WikidataAllPropTable } from "@slub/edb-advanced-components"; import WikidataThingCard from "./WikidataThingCard"; import WikidataHumanCard from "./WikidataHumanCard"; -import WikidateAllPropTable from "./WikidataAllPropTable"; export default { - title: "form/wikidata/WikidataThingCard", + title: "ui/view/WikidataCard", component: WikidataThingCard, }; @@ -22,7 +22,7 @@ export const WikidataHumanCardDschuong = () => ( ); export const WikidateAllPropTableDschuang = () => ( - + ); export const WikidataThingCardHuman = () => ( diff --git a/apps/exhibition-live/components/form/wikidata/WikidataAutocompleteInput.stories.tsx b/apps/exhibition-live/components/form/wikidata/WikidataAutocompleteInput.stories.tsx index af82cd2f..aa8ea862 100644 --- a/apps/exhibition-live/components/form/wikidata/WikidataAutocompleteInput.stories.tsx +++ b/apps/exhibition-live/components/form/wikidata/WikidataAutocompleteInput.stories.tsx @@ -3,7 +3,7 @@ import React from "react"; import WikidataAutocompleteInput from "./WikidataAutocompleteInput"; export default { - title: "form/wikidata/WikidataAutoCompleteInput", + title: "ui/form/WikidataAutoCompleteInput", component: WikidataAutocompleteInput, }; diff --git a/apps/exhibition-live/components/form/wikidata/WikidataAutocompleteInput.tsx b/apps/exhibition-live/components/form/wikidata/WikidataAutocompleteInput.tsx index e2065312..46c16bba 100644 --- a/apps/exhibition-live/components/form/wikidata/WikidataAutocompleteInput.tsx +++ b/apps/exhibition-live/components/form/wikidata/WikidataAutocompleteInput.tsx @@ -1,4 +1,3 @@ -import { Typography } from "@mui/material"; import parse from "html-react-parser"; import React, { FunctionComponent, @@ -9,19 +8,15 @@ import React, { } from "react"; import { - remoteSparqlQuery, - sparqlSelectViaFieldMappings, -} from "../../utils/sparql"; -import { - findPersonWithinWikidataUsingREST, + findWithinWikidataUsingREST, wikidataPrefixes, -} from "../../utils/wikidata"; -import { - AutocompleteSuggestion, - DebouncedAutocomplete, -} from "../DebouncedAutoComplete"; +} from "@slub/edb-ui-utils"; import WikidataHumanCard from "./WikidataHumanCard"; import WikidataThingCard from "./WikidataThingCard"; +import { sparqlSelectViaFieldMappings } from "@slub/sparql-schema"; +import { remoteSparqlQuery } from "@slub/remote-query-implementations"; +import { DebouncedAutocomplete } from "@slub/edb-advanced-components"; +import { AutocompleteSuggestion } from "@slub/edb-core-types"; interface OwnProps { selected?: AutocompleteSuggestion | null; @@ -102,13 +97,7 @@ const WikidataAutocompleteInput: FunctionComponent = ({ minSearchLength={3} load={async (searchString) => searchString - ? ( - await findPersonWithinWikidataUsingREST( - searchString, - 10, - classType, - ) - ) + ? (await findWithinWikidataUsingREST(searchString, classType, 10)) .map((d) => { return d; }) diff --git a/apps/exhibition-live/components/form/wikidata/WikidataHumanCard.tsx b/apps/exhibition-live/components/form/wikidata/WikidataHumanCard.tsx index 7eac41e2..86488703 100644 --- a/apps/exhibition-live/components/form/wikidata/WikidataHumanCard.tsx +++ b/apps/exhibition-live/components/form/wikidata/WikidataHumanCard.tsx @@ -23,12 +23,10 @@ import React, { useState, } from "react"; -import { - remoteSparqlQuery, - sparqlSelectViaFieldMappings, -} from "../../utils/sparql"; -import { wikidataPrefixes } from "../../utils/wikidata"; -import WikidataAllPropTable from "./WikidataAllPropTable"; +import { wikidataPrefixes } from "@slub/edb-ui-utils"; +import { sparqlSelectViaFieldMappings } from "@slub/sparql-schema"; +import { remoteSparqlQuery } from "@slub/remote-query-implementations"; +import { WikidataAllPropTable } from "@slub/edb-advanced-components"; interface OwnProps { personIRI?: string | null; diff --git a/apps/exhibition-live/components/form/wikidata/WikidataThingCard.tsx b/apps/exhibition-live/components/form/wikidata/WikidataThingCard.tsx index 2aa3a298..25ce6ae6 100644 --- a/apps/exhibition-live/components/form/wikidata/WikidataThingCard.tsx +++ b/apps/exhibition-live/components/form/wikidata/WikidataThingCard.tsx @@ -15,12 +15,10 @@ import React, { useState, } from "react"; -import { - remoteSparqlQuery, - sparqlSelectViaFieldMappings, -} from "../../utils/sparql"; -import { wikidataPrefixes } from "../../utils/wikidata"; -import WikidataAllPropTable from "./WikidataAllPropTable"; +import { wikidataPrefixes } from "@slub/edb-ui-utils"; +import { sparqlSelectViaFieldMappings } from "@slub/sparql-schema"; +import { remoteSparqlQuery } from "@slub/remote-query-implementations"; +import { WikidataAllPropTable } from "@slub/edb-advanced-components"; interface OwnProps { thingIRI?: string | null; diff --git a/apps/exhibition-live/components/google/ColumnChip.tsx b/apps/exhibition-live/components/google/ColumnChip.tsx new file mode 100644 index 00000000..8f8a6384 --- /dev/null +++ b/apps/exhibition-live/components/google/ColumnChip.tsx @@ -0,0 +1,121 @@ +import { useTranslation } from "next-i18next"; +import React, { useCallback, useMemo } from "react"; +import { + DeclarativeFlatMapping, + DeclarativeFlatMappings, + DeclarativeMatchBasedFlatMapping, + DeclarativeMatchBasedFlatMappings, +} from "@slub/edb-data-mapping"; +import NiceModal from "@ebay/nice-modal-react"; +import { SpreadSheetTable } from "./SpreadSheetTable"; +import { Chip, Divider, Menu, MenuItem } from "@mui/material"; +import { OwnColumnDesc } from "./types"; +import { CachedWorkSheet, CellTypeLike } from "./useCachedWorkSheet"; +import { NiceMappingConfigurationDialog } from "./NiceMappingConfigurationDialog"; + +export type ColumnChipProps = { + columnIndex: number; + columnLetter: string; + columnDesc: OwnColumnDesc[]; + value: any; + label: string; + spreadSheetMapping?: DeclarativeFlatMappings; + rawMapping?: DeclarativeMatchBasedFlatMappings; + workSheet: CachedWorkSheet; +}; +export const ColumnChip = ({ + label, + columnIndex, + columnLetter, + columnDesc, + spreadSheetMapping, + rawMapping, + workSheet, +}: ColumnChipProps) => { + const { t } = useTranslation(); + + const [anchorEl, setAnchorEl] = React.useState(null); + const open = Boolean(anchorEl); + const columnMapping = useMemo( + () => + spreadSheetMapping?.filter((mapping) => + Boolean( + (mapping.source.columns as any)?.find((col) => + typeof col === "string" + ? col === columnLetter + : col === columnIndex, + ), + ), + ) || [], + [spreadSheetMapping, columnIndex, columnLetter], + ); + const handleClick = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget); + }; + const handleClose = () => { + setAnchorEl(null); + }; + + const handleAssignMapping = useCallback(() => {}, []); + const handleOpenMapping = useCallback( + ( + mappingDecl: DeclarativeFlatMapping, + rawMapping?: DeclarativeMatchBasedFlatMapping, + ) => { + NiceModal.show(NiceMappingConfigurationDialog, { + mapping: mappingDecl, + rawMapping, + sourcePath: columnIndex, + fields: columnDesc, + tablePreview: (mapping: DeclarativeFlatMapping) => { + return ( + + ); + }, + }); + }, + [columnIndex, workSheet, columnDesc], + ); + + return ( + <> + 0 ? "primary" : undefined} + sx={{ margin: "0.2rem" }} + onClick={handleClick} + /> + + + {t("assign mapping")} + + + {columnMapping.map((mapping, index) => { + const raw = rawMapping?.find( + (rawMappingDecl) => rawMappingDecl.id === mapping.id, + ); + return ( + handleOpenMapping(mapping, raw)} + > + {t("open Mapping", { index: index + 1 })} + + ); + })} + + + ); +}; diff --git a/apps/exhibition-live/components/google/GoogleDrivePicker.tsx b/apps/exhibition-live/components/google/GoogleDrivePicker.tsx index de5861f3..07db2fc3 100644 --- a/apps/exhibition-live/components/google/GoogleDrivePicker.tsx +++ b/apps/exhibition-live/components/google/GoogleDrivePicker.tsx @@ -1,24 +1,33 @@ -import React, { useCallback, useMemo } from "react"; +import React, { useCallback, useMemo, useState } from "react"; import type { FC } from "react"; import { AppBar, + Avatar, Box, Button, Dialog, DialogActions, DialogContent, + Grid, IconButton, List, ListItem, + ListItemAvatar, + ListItemButton, + ListItemText, Toolbar, Typography, } from "@mui/material"; -import { useQuery } from "@tanstack/react-query"; +import { useQuery } from "@slub/edb-state-hooks"; import { useGoogleToken } from "./useGoogleToken"; -import { GenericMaterialListItem } from "../content/main/GenericVirtualizedList"; -import NiceModal, { useModal } from "@ebay/nice-modal-react"; import { Close as CloseIcon } from "@mui/icons-material"; -import { useSettings } from "../state/useLocalSettings"; +import { useSettings } from "@slub/edb-state-hooks"; +import { useGoogleOAuth } from "@react-oauth/google"; +import NiceModal, { useModal } from "@ebay/nice-modal-react"; +import { GenericMaterialListItem } from "@slub/edb-virtualized-components"; +import { useGoogleSpreadSheet } from "./useGoogleSpreadSheet"; +import { mappingsAvailable } from "./mappingsAvailable"; +import { useTranslation } from "next-i18next"; const googleApiURL = "https://content.googleapis.com/drive/v3/files"; const mimeIconsBase = @@ -43,7 +52,7 @@ const getMimeIcon = (mimeType: string, size: number = 128) => { type GoogleDrivePickerProps = { supportedMimeTypes?: string[]; - onPicked: (documentId: string) => void; + onPicked: (documentId: string, sheetId: number, mappingId: string) => void; }; export const GoogleDrivePicker: FC = ({ onPicked, @@ -51,12 +60,12 @@ export const GoogleDrivePicker: FC = ({ }) => { const { credentials } = useGoogleToken(); const { googleDrive } = useSettings(); + const { clientId } = useGoogleOAuth(); + const { t } = useTranslation(); const { data: files } = useQuery( ["files"], async () => { - const key = - googleDrive?.apiKey || - (process.env.NEXT_PUBLIC_GAPI_API_KEY as string | undefined); + const key = clientId || googleDrive?.apiKey; if (!key) { throw new Error("No API Key provided"); } @@ -91,34 +100,97 @@ export const GoogleDrivePicker: FC = ({ })); }, [files]); - const handleOpenDocument = useCallback( + const [selectedFileID, setSelectedFileID] = useState(); + + const { sheetsByIndex, loaded } = useGoogleSpreadSheet(selectedFileID); + + const [selectedSheetID, setSelectedSheetID] = useState(0); + + const handleSelectFile = useCallback( (file: any) => { - onPicked(file.id); + setSelectedSheetID(undefined); + setSelectedFileID(file.id); + }, + [setSelectedFileID, setSelectedSheetID], + ); + const handleSelectSheet = useCallback( + (sheetID: number) => { + setSelectedSheetID(sheetID); + }, + [setSelectedSheetID], + ); + const handleOpenDocument = useCallback( + (mappingId: string) => { + onPicked(selectedFileID, selectedSheetID, mappingId); }, - [onPicked], + [onPicked, selectedFileID, selectedSheetID], ); return ( - - - {fileList?.map((file: any, index: number) => ( - - handleOpenDocument(file) - : undefined - } - id={file.id} - primary={file.name} - /> - - ))} - - + + + {t("Files")} + + {fileList?.map((file: any, index: number) => ( + + handleSelectFile(file) + : undefined + } + id={file.id} + primary={file.name} + /> + + ))} + + + {selectedFileID && sheetsByIndex.length > 0 && ( + + {t("Worksheets")} + + {sheetsByIndex.map((sheet, index) => ( + handleSelectSheet(sheet.sheetId)} + > + + + {index + 1} + + + {sheet.title} + + ))} + + + )} + {selectedFileID && selectedSheetID !== undefined && ( + + {t("Mappings")} + + {mappingsAvailable.map((key, index) => ( + handleOpenDocument(key)}> + + + {index + 1} + + + {key} + + ))} + + + )} + ); }; @@ -130,6 +202,7 @@ export const GoogleDrivePickerModal = NiceModal.create(({}) => { open={modal.visible} onClose={() => modal.remove()} fullWidth={true} + maxWidth={false} scroll={"paper"} disableScrollLock={false} > @@ -153,8 +226,8 @@ export const GoogleDrivePickerModal = NiceModal.create(({}) => { { - modal.resolve(documentId); + onPicked={(documentId: string, sheetId, mappingId) => { + modal.resolve({ documentId, sheetId, mappingId }); modal.remove(); }} supportedMimeTypes={["application/vnd.google-apps.spreadsheet"]} diff --git a/apps/exhibition-live/components/google/GoogleOAuth.tsx b/apps/exhibition-live/components/google/GoogleOAuth.tsx index 910a00b5..52f62eee 100644 --- a/apps/exhibition-live/components/google/GoogleOAuth.tsx +++ b/apps/exhibition-live/components/google/GoogleOAuth.tsx @@ -2,12 +2,11 @@ import { hasGrantedAnyScopeGoogle, TokenResponse, useGoogleLogin, + useGoogleOneTapLogin, } from "@react-oauth/google"; import { Button } from "@mui/material"; -import { FC, useCallback, useEffect } from "react"; +import { FC, useCallback, useEffect, useMemo } from "react"; import { useGoogleToken } from "./useGoogleToken"; -import { GoogleDrivePicker, GoogleDrivePickerModal } from "./GoogleDrivePicker"; -import NiceModal from "@ebay/nice-modal-react"; type LoginProps = { scopes: string[]; @@ -17,6 +16,16 @@ export const Login: FC = ({ scopes }) => { useEffect(() => { init(); }, [init]); + + useGoogleOneTapLogin({ + onSuccess: (credentialResponse) => { + console.log(credentialResponse); + }, + onError: () => { + console.log("Login Failed"); + }, + auto_select: true, + }); const login = useGoogleLogin({ scope: scopes.join(" "), onSuccess: ( @@ -32,10 +41,27 @@ export const Login: FC = ({ scopes }) => { }, }); + const granted = useMemo( + () => + typeof window !== "undefined" && + hasGrantedAnyScopeGoogle( + credentials, + ...(scopes as [string, string, string]), + ), + [credentials, scopes], + ); + useEffect(() => { + console.log({ credentials }); + if (credentials?.access_token) { + //console.log("logged in"); + //login(); + } + }, [credentials, login]); + const logout = useCallback(() => { clear(); }, [clear]); - return credentials?.access_token ? ( + return credentials?.access_token && granted ? ( <> You have access to the users drive diff --git a/apps/exhibition-live/components/google/GoogleSpreadSheetContainer.tsx b/apps/exhibition-live/components/google/GoogleSpreadSheetContainer.tsx new file mode 100644 index 00000000..122ad9d9 --- /dev/null +++ b/apps/exhibition-live/components/google/GoogleSpreadSheetContainer.tsx @@ -0,0 +1,32 @@ +import React, { FC } from "react"; +import { useGoogleSpreadSheet } from "./useGoogleSpreadSheet"; +import { Box } from "@mui/material"; +import { SpreadSheetWorkSheetView } from "./SpreadSheetWorkSheetView"; + +export type GoogleSpreadSheetContainerProps = { + documentId: string; + sheetId: number; + mappingId: string; +}; +export const GoogleSpreadSheetContainer: FC< + GoogleSpreadSheetContainerProps +> = ({ documentId, sheetId, mappingId }) => { + const { sheetsById, loaded } = useGoogleSpreadSheet(documentId); + return ( + loaded && ( + + + + ) + ); +}; diff --git a/apps/exhibition-live/components/google/MappedItem.tsx b/apps/exhibition-live/components/google/MappedItem.tsx new file mode 100644 index 00000000..8ee562aa --- /dev/null +++ b/apps/exhibition-live/components/google/MappedItem.tsx @@ -0,0 +1,98 @@ +import { mapByConfigFlat } from "@slub/edb-data-mapping"; +import type { DeclarativeFlatMappings } from "@slub/edb-data-mapping"; +import { CachedWorkSheet, CellTypeLike } from "./useCachedWorkSheet"; +import { CRUDFunctions } from "@slub/edb-core-types"; +import { useAdbContext, useQuery } from "@slub/edb-state-hooks"; +import React, { useCallback } from "react"; +import { useTranslation } from "next-i18next"; +import { CircularProgress, List } from "@mui/material"; +import { TypedListItem } from "@slub/edb-advanced-components"; +import { makeDefaultMappingStrategyContext } from "@slub/edb-ui-utils"; + +export type MappedItemProps = { + path: string; + index: number; + spreadSheetMapping: DeclarativeFlatMappings; + workSheet: CachedWorkSheet; + crudOptions?: CRUDFunctions; +}; +export const MappedItem = ({ + path, + index, + spreadSheetMapping, + workSheet, + crudOptions, +}: MappedItemProps) => { + const { + queryBuildOptions: { prefixes, primaryFields }, + createEntityIRI, + typeNameToTypeIRI, + typeIRIToTypeName, + jsonLDConfig: { defaultPrefix }, + components: { EntityDetailModal }, + normDataMapping, + } = useAdbContext(); + const mapData = useCallback(async () => { + console.log("will map row", index); + try { + const targetData = { + __index: index, + "@id": createEntityIRI("Exhibition"), + "@type": typeNameToTypeIRI("Exhibition"), + }; + console.log("will map by config"); + const mappedData = await mapByConfigFlat( + (col: number | string) => { + const cell = workSheet.getCell(index, col as number); + return cell.value as string; + }, + targetData, + spreadSheetMapping, + makeDefaultMappingStrategyContext( + crudOptions?.selectFetch, + { + defaultPrefix, + prefixes, + }, + createEntityIRI, + typeIRIToTypeName, + primaryFields, + normDataMapping, + ), + ); + return mappedData; + } catch (e) { + console.warn("failed to map row", index, e); + } + return null; + }, [ + workSheet, + crudOptions, + spreadSheetMapping, + primaryFields, + index, + createEntityIRI, + defaultPrefix, + prefixes, + typeIRIToTypeName, + normDataMapping, + ]); + + const { data, isLoading } = useQuery(["mappedData", path], mapData, { + enabled: workSheet.loaded && spreadSheetMapping.length > 0, + staleTime: 1000 * 60 * 2, // 2 minutes, + }); + const { t } = useTranslation(); + + return isLoading ? ( + <> + + + ) : ( + + {data?.["@type"] && ( + + )} + + ); +}; diff --git a/apps/exhibition-live/components/mapping/NiceMappingConfigurationDialog.tsx b/apps/exhibition-live/components/google/NiceMappingConfigurationDialog.tsx similarity index 92% rename from apps/exhibition-live/components/mapping/NiceMappingConfigurationDialog.tsx rename to apps/exhibition-live/components/google/NiceMappingConfigurationDialog.tsx index aa3a6fa7..29c02aec 100644 --- a/apps/exhibition-live/components/mapping/NiceMappingConfigurationDialog.tsx +++ b/apps/exhibition-live/components/google/NiceMappingConfigurationDialog.tsx @@ -18,17 +18,19 @@ import { useTranslation } from "next-i18next"; import { DeclarativeMatchBasedFlatMapping, matchBased2DeclarativeFlatMapping, -} from "../utils/mapping/mapMatchBasedByConfig"; -import { OwnColumnDesc } from "../google/types"; +} from "@slub/edb-data-mapping"; import { JsonView } from "react-json-view-lite"; -import { DeclarativeFlatMapping } from "../utils/mapping/mappingStrategies"; -import { parseJSONObject } from "../utils/core/parseJSON"; +import { DeclarativeFlatMapping } from "@slub/edb-data-mapping"; +import { parseJSONObject } from "@slub/edb-ui-utils"; +import { OwnColumnDesc } from "./types"; +import { CachedWorkSheet } from "./useCachedWorkSheet"; type NiceMappingConfigurationDialogProps = { mapping: any; rawMapping?: DeclarativeMatchBasedFlatMapping; fields?: OwnColumnDesc[]; sourcePath: string | number; + worksheet?: CachedWorkSheet; tablePreview?: (mapping: DeclarativeFlatMapping) => React.ReactElement; }; @@ -38,6 +40,7 @@ export const NiceMappingConfigurationDialog = NiceModal.create( sourcePath, rawMapping, fields, + worksheet, tablePreview, }: NiceMappingConfigurationDialogProps) => { const modal = useModal(); @@ -138,6 +141,7 @@ export const NiceMappingConfigurationDialog = NiceModal.create( {TablePreview} )} + diff --git a/apps/exhibition-live/components/google/SpreadSheetTable.tsx b/apps/exhibition-live/components/google/SpreadSheetTable.tsx new file mode 100644 index 00000000..5413d4c7 --- /dev/null +++ b/apps/exhibition-live/components/google/SpreadSheetTable.tsx @@ -0,0 +1,100 @@ +import { CachedWorkSheet, CellTypeLike } from "./useCachedWorkSheet"; +import React, { useEffect, useMemo, useState } from "react"; +import { + MaterialReactTable, + MRT_ColumnDef, + useMaterialReactTable, +} from "material-react-table"; +import { OwnColumnDesc } from "./types"; +import { Box, Skeleton } from "@mui/material"; +import { index2letter } from "@slub/edb-core-utils"; + +export type SpreadSheetTableProps = { + workSheet: CachedWorkSheet; + columnIndicies: number[]; +}; +export const SpreadSheetTable = ({ + workSheet, + columnIndicies, +}: SpreadSheetTableProps) => { + const loaded = workSheet.loaded; + const [pagination, setPagination] = useState({ + pageIndex: 0, + pageSize: 5, + }); + const [columns, setColumns] = useState[]>([]); + const [columnDesc, setColumnDesc] = useState([]); + const reducedColumns = useMemo(() => { + return columns.filter((column, index) => columnIndicies.includes(index)); + }, [columns, columnIndicies]); + + useEffect(() => { + (async () => { + if (!loaded) return; + try { + const cells = [...Array(workSheet.columnCount)].map((_, index) => { + return workSheet.getCell(0, index); + }); + const columnDesc_ = cells.map((cell, index) => ({ + index, + value: cell.value, + letter: index2letter(index), + })); + setColumnDesc(columnDesc_); + const cols = cells.map((cell, index) => { + return { + id: (cell.value ?? "").toString() + index, + header: (cell.value ?? "").toString(), + accessorFn: (originalRow, rowIndex) => { + try { + const dataCell = workSheet.getCell(originalRow + 1, index); + return dataCell?.value ?? null; + } catch (e) { + return null; + } + }, + }; + }); + setColumns(cols as MRT_ColumnDef[]); + } catch (e) { + console.log(e); + } + })(); + }, [workSheet, loaded, setColumnDesc]); + + const rowCount = useMemo( + () => Math.ceil(workSheet.rowCount - 2), + [workSheet], + ); + const isLastRow = rowCount - 2 <= pagination.pageSize * pagination.pageIndex; + const amountOfFakeRows = + rowCount <= 0 + ? 0 + : isLastRow + ? rowCount % pagination.pageSize + : pagination.pageSize; + const fakeData = [...Array(amountOfFakeRows)].map( + (_, index) => index + pagination.pageIndex * pagination.pageSize, + ); + + const materialTable = useMaterialReactTable({ + // @ts-ignore + columns: reducedColumns, + data: fakeData, + rowCount, + manualPagination: true, + // @ts-ignore + onPaginationChange: setPagination, + state: { + pagination, + }, + }); + + return loaded ? ( + + + + ) : ( + + ); +}; diff --git a/apps/exhibition-live/components/google/SpreadSheetView.tsx b/apps/exhibition-live/components/google/SpreadSheetView.tsx deleted file mode 100644 index 105abe89..00000000 --- a/apps/exhibition-live/components/google/SpreadSheetView.tsx +++ /dev/null @@ -1,1038 +0,0 @@ -import React, { FC, useCallback, useEffect, useMemo, useState } from "react"; -import { - GoogleSpreadsheet, - GoogleSpreadsheetCell, - GoogleSpreadsheetWorksheet, -} from "google-spreadsheet"; -import { useGoogleToken } from "./useGoogleToken"; -import NiceModal, { useModal } from "@ebay/nice-modal-react"; -import { - AppBar, - Box, - Button, - Checkbox, - Chip, - CircularProgress, - Dialog, - DialogActions, - DialogContent, - Divider, - FormControl, - Grid, - IconButton, - List, - Menu, - MenuItem, - Select, - Skeleton, - Tab, - Tabs, - TextField, - Toolbar, - Typography, -} from "@mui/material"; -import { Close as CloseIcon } from "@mui/icons-material"; -import { v4 as uuidv4 } from "uuid"; -import { - MaterialReactTable, - MRT_ColumnDef, - useMaterialReactTable, -} from "material-react-table"; -import { mapByConfigFlat } from "../utils/mapping/mapByConfig"; -import { spreadSheetMappings } from "../config/spreadSheetMappings"; -import { declarativeMappings } from "../config"; -import { makeDefaultMappingStrategyContext } from "../form/SimilarityFinder"; -import { useGlobalCRUDOptions } from "../state/useGlobalCRUDOptions"; -import { encodeIRI, filterUndefOrNull } from "../utils/core"; -import { useQuery } from "@tanstack/react-query"; -import { OwnColumnDesc } from "./types"; -import TypedListItem from "../content/list/TypedListItem"; -import { sladb, slent } from "../form/formConfigs"; -import HorizontalNonLinearStepper from "../form/wizard/HorizontalNonLinearStepper"; -import { useCRUDWithQueryClient } from "../state/useCRUDWithQueryClient"; -import useExtendedSchema from "../state/useExtendedSchema"; -import { JSONSchema7 } from "json-schema"; -import { useRouter } from "next/router"; -import FormControlLabel from "@mui/material/FormControlLabel"; -import { - DeclarativeFlatMapping, - DeclarativeFlatMappings, -} from "../utils/mapping/mappingStrategies"; -import { useTranslation } from "next-i18next"; -import { NiceMappingConfigurationDialog } from "../mapping/NiceMappingConfigurationDialog"; -import { - DeclarativeMatchBasedFlatMapping, - DeclarativeMatchBasedFlatMappings, -} from "../utils/mapping/mapMatchBasedByConfig"; -import { CRUDFunctions } from "@slub/edb-core-types"; - -//we will create a cashed worksheet, were selectively rows are preloaded and once loaded use for a certain stale time -type CachedWorkSheet = { - loaded: boolean; - title: string; - sheetId: number; - index: number; - rowCount: number; - columnCount: number; - preloadCells: ( - startRowIndex?: number, - endRowIndex?: number, - startColumnIndex?: number, - endColumnIndex?: number, - ) => Promise; - getCell: (rowIndex: number, columnIndex: number) => GoogleSpreadsheetCell; -}; - -type UseCachedWorkSheetOptions = { - workSheet: GoogleSpreadsheetWorksheet; - staleTime?: number; - autoCache?: boolean; -}; - -const useCashedWorkSheet = ({ - workSheet, - staleTime = 1000 * 60 * 5, - autoCache, -}: UseCachedWorkSheetOptions): CachedWorkSheet => { - const [loaded, setLoaded] = useState(false); - const [rowCount, setRowCount] = useState(0); - const [columnCount, setColumnCount] = useState(0); - const [title, setTitle] = useState(""); - - const getCell = useCallback( - (rowIndex: number, columnIndex: number) => { - try { - return workSheet.getCell(rowIndex, columnIndex); - } catch (e) { - console.error("failed to load cell", e); - return null; - } - }, - [workSheet], - ); - - const preloadCells = useCallback( - async ( - startRowIndex = 0, - endRowIndex = 10, - startColumnIndex = 0, - endColumnIndex = 10, - ) => { - console.log("will load cells", { - startRowIndex, - endRowIndex, - startColumnIndex, - endColumnIndex, - }); - try { - await workSheet.loadCells({ - startRowIndex, - endRowIndex, - startColumnIndex, - endColumnIndex, - }); - } catch (e) { - console.error("failed to load cells", e); - setTimeout(() => { - console.log("retrying to load cells"); - setLoaded(true); - }, 1); - return; - } - setLoaded(true); - }, - [workSheet, setLoaded], - ); - - useEffect(() => { - (async () => { - setRowCount(workSheet.rowCount); - setColumnCount(workSheet.columnCount); - setTitle(workSheet.title); - })(); - }, [workSheet, setLoaded, setRowCount, setColumnCount, setTitle]); - - useEffect(() => { - if (autoCache && !loaded) { - preloadCells(0, workSheet.rowCount, 0, workSheet.columnCount); - } - }, [ - workSheet.rowCount, - workSheet.columnCount, - autoCache, - loaded, - preloadCells, - ]); - - return { - loaded, - title, - sheetId: workSheet.sheetId, - index: workSheet.index, - rowCount, - columnCount, - preloadCells, - getCell, - }; -}; - -type GoogleSpreadSheetTableProps = { - workSheet: CachedWorkSheet; - columnIndicies: number[]; -}; - -export const GoogleSpreadSheetTable: FC = ({ - workSheet, - columnIndicies, -}) => { - const loaded = workSheet.loaded; - const [pagination, setPagination] = useState({ - pageIndex: 0, - pageSize: 5, - }); - const [columns, setColumns] = useState[]>([]); - const [columnDesc, setColumnDesc] = useState([]); - const reducedColumns = useMemo(() => { - return columns.filter((column, index) => columnIndicies.includes(index)); - }, [columns, columnIndicies]); - - useEffect(() => { - (async () => { - if (!loaded) return; - try { - const cells = [...Array(workSheet.columnCount)].map((_, index) => { - return workSheet.getCell(0, index); - }); - const columnDesc_ = cells.map((cell, index) => ({ - index, - value: cell.value, - letter: index2letter(index), - })); - setColumnDesc(columnDesc_); - const cols = cells.map((cell, index) => { - return { - id: (cell.value ?? "").toString() + index, - header: (cell.value ?? "").toString(), - accessorFn: (originalRow, rowIndex) => { - try { - const dataCell = workSheet.getCell(originalRow + 1, index); - return dataCell?.value ?? null; - } catch (e) { - return null; - } - }, - }; - }); - setColumns(cols as MRT_ColumnDef[]); - } catch (e) { - console.log(e); - } - })(); - }, [workSheet, loaded, setColumnDesc]); - - const rowCount = useMemo( - () => Math.ceil(workSheet.rowCount - 2), - [workSheet], - ); - // needs to be just the right amount of rows: so full pageSize but a the end the Rest of the rowCount divided by pageSize - const isLastRow = rowCount - 2 <= pagination.pageSize * pagination.pageIndex; - const amountOfFakeRows = - rowCount <= 0 - ? 0 - : isLastRow - ? rowCount % pagination.pageSize - : pagination.pageSize; - const fakeData = [...Array(amountOfFakeRows)].map( - (_, index) => index + pagination.pageIndex * pagination.pageSize, - ); - - const materialTable = useMaterialReactTable({ - // @ts-ignore - columns: reducedColumns, - data: fakeData, - rowCount, - manualPagination: true, - // @ts-ignore - onPaginationChange: setPagination, - state: { - pagination, - }, - }); - - return loaded ? ( - - - - ) : ( - - ); -}; - -type ColumnChipProps = { - columnIndex: number; - columnLetter: string; - columnDesc: OwnColumnDesc[]; - value: any; - label: string; - spreadSheetMapping?: DeclarativeFlatMappings; - rawMapping?: DeclarativeMatchBasedFlatMappings; - workSheet: CachedWorkSheet; -}; -const ColumnChip = ({ - label, - columnIndex, - columnLetter, - columnDesc, - spreadSheetMapping, - rawMapping, - workSheet, -}: ColumnChipProps) => { - const { t } = useTranslation(); - - const [anchorEl, setAnchorEl] = React.useState(null); - const open = Boolean(anchorEl); - const columnMapping = useMemo( - () => - spreadSheetMapping?.filter((mapping) => - Boolean( - (mapping.source.columns as any)?.find((col) => - typeof col === "string" - ? col === columnLetter - : col === columnIndex, - ), - ), - ) || [], - [spreadSheetMapping, columnIndex, columnLetter], - ); - const handleClick = (event: React.MouseEvent) => { - setAnchorEl(event.currentTarget); - }; - const handleClose = () => { - setAnchorEl(null); - }; - - const handleAssignMapping = useCallback(() => {}, []); - const handleOpenMapping = useCallback( - ( - mappingDecl: DeclarativeFlatMapping, - rawMapping?: DeclarativeMatchBasedFlatMapping, - ) => { - NiceModal.show(NiceMappingConfigurationDialog, { - mapping: mappingDecl, - rawMapping, - sourcePath: columnIndex, - fields: columnDesc, - tablePreview: (mapping: DeclarativeFlatMapping) => { - return ( - - ); - }, - }); - }, - [columnIndex, workSheet, columnDesc], - ); - - return ( - <> - 0 ? "primary" : undefined} - sx={{ margin: "0.2rem" }} - onClick={handleClick} - /> - - - {t("assign mapping")} - - - {columnMapping.map((mapping, index) => { - const raw = rawMapping?.find( - (rawMappingDecl) => rawMappingDecl.id === mapping.id, - ); - return ( - handleOpenMapping(mapping, raw)} - > - {t("open Mapping", { index: index + 1 })} - - ); - })} - - - ); -}; - -type MappedItemProps = { - path: string; - index: number; - spreadSheetMapping: DeclarativeFlatMappings; - workSheet: CachedWorkSheet; - crudOptions?: CRUDFunctions; -}; - -const MappedItem = ({ - path, - index, - spreadSheetMapping, - workSheet, - crudOptions, -}: MappedItemProps) => { - const mapData = useCallback(async () => { - try { - const targetData = { - __index: index, - "@id": `${slent().value}${uuidv4()}`, - "@type": sladb.Exhibition.value, - }; - console.log("will map by config"); - const mappedData = await mapByConfigFlat( - (col: number | string) => { - const cell = workSheet.getCell(index, col as number); - return cell.value as string; - }, - targetData, - spreadSheetMapping, - makeDefaultMappingStrategyContext( - crudOptions?.selectFetch, - declarativeMappings, - ), - ); - return mappedData; - } catch (e) { - console.warn("failed to map row", index, e); - } - return null; - }, [workSheet, crudOptions, spreadSheetMapping, index]); - - const { data, isLoading } = useQuery(["mappedData", path], mapData, { - enabled: workSheet.loaded && spreadSheetMapping.length > 0, - staleTime: 1000 * 60 * 2, // 2 minutes, - }); - const { t } = useTranslation(); - - return isLoading ? ( - - ) : ( - - {data?.["@type"] && ( - - )} - - ); -}; - -export const index2letter = (index: number): string => { - const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - const mod = index % alphabet.length; - const rest = (index - mod) / alphabet.length; - const letter = alphabet[mod]; - return rest > 0 ? index2letter(rest) + letter : letter; -}; - -export type SpreadSheetWorkSheetViewProps = { - workSheet: GoogleSpreadsheetWorksheet; - selectedSheet: number; -}; -const typeName = "Exhibition"; -const classIRI = sladb.Exhibition.value; -const mappingsAvailable = Object.keys(spreadSheetMappings); -export const GoogleSpeadSheetWorkSheetView: FC< - SpreadSheetWorkSheetViewProps -> = ({ workSheet: workSheetOriginal, selectedSheet }) => { - const workSheet = useCashedWorkSheet({ - workSheet: workSheetOriginal, - autoCache: true, - }); - const loaded = workSheet.loaded; - const [_loaded, setLoaded] = useState(false); - const [pagination, setPagination] = useState({ - pageIndex: 0, - pageSize: 5, - }); - const [columns, setColumns] = useState[]>([]); - const [reducedColumns, setReducedColumns] = useState[]>( - [], - ); - const [maxColumns, setMaxColumns] = useState(10); - const [showTable, setShowTable] = useState(false); - const [columnDesc, setColumnDesc] = useState([]); - const [writeToSpreadSheet, setWriteToSpreadSheet] = useState(false); - - const [rawMappedData, setRawMappedData] = useState([]); - const locale = useRouter().locale ?? "de"; - const [selectedMapping, setSelectedMapping] = useState( - mappingsAvailable[0], - ); - const { crudOptions } = useGlobalCRUDOptions(); - const spreadSheetMapping = useMemo(() => { - let final: { - raw?: DeclarativeMatchBasedFlatMappings; - mapping: DeclarativeFlatMappings; - } = { - mapping: [], - }; - try { - const cSpreadSheetMapping = spreadSheetMappings[selectedMapping]; - final = - columnDesc.length <= 0 || !cSpreadSheetMapping - ? final - : { - raw: cSpreadSheetMapping.raw, - mapping: cSpreadSheetMapping.fieldMapping(columnDesc), - }; - } catch (e) { - console.error( - "failed to apply declarative mapping to column description", - e, - ); - } - return final; - }, [columnDesc, selectedMapping]); - - useEffect(() => { - setReducedColumns(columns?.slice(0, maxColumns) || []); - }, [columns, maxColumns, setReducedColumns]); - - const calculateMapping = useCallback(async () => { - if (!workSheet.loaded) return; - try { - const cells = [...Array(workSheet.columnCount)].map((_, index) => { - return workSheet.getCell(0, index); - }); - const columnDesc_ = cells.map((googleSpreadSheetCell, index) => ({ - index, - value: googleSpreadSheetCell?.value || null, - letter: index2letter(index), - })); - setColumnDesc(columnDesc_); - const mappedCol = { - id: "-1", - header: "mapped Data", - accessorFn: (originalRow, rowIndex) => { - return originalRow + 1; - }, - Cell: ({ cell }) => { - const rowIndex = cell.getValue(); - const pathSegments = [ - workSheet.sheetId, - String(workSheet.index), - String(rowIndex), - ]; - - return ( - - ); - }, - }; - const cols = cells.map((cell, index) => { - return { - id: (cell.value ?? "").toString() + index, - header: (cell.value ?? "").toString(), - accessorFn: (originalRow, rowIndex) => { - try { - const dataCell = workSheet.getCell(originalRow + 1, index); - return dataCell?.value ?? null; - } catch (e) { - return null; - } - }, - }; - }); - setColumns([mappedCol, ...cols] as MRT_ColumnDef[]); - const sheetTitle = workSheet.title; - if (mappingsAvailable.includes(sheetTitle)) { - setSelectedMapping(sheetTitle); - } - } catch (e) { - console.log(e); - } - setLoaded(true); - }, [ - workSheet, - crudOptions, - spreadSheetMapping.mapping, - setLoaded, - setColumnDesc, - setSelectedMapping, - ]); - - const rowCount = useMemo( - () => Math.ceil(workSheet.rowCount - 2), - [workSheet.rowCount], - ); - // needs to be just the right amount of rows: so full pageSize but a the end the Rest of the rowCount divided by pageSize - const isLastRow = rowCount - 2 <= pagination.pageSize * pagination.pageIndex; - const amountOfFakeRows = - rowCount <= 0 - ? 0 - : isLastRow - ? rowCount % pagination.pageSize - : pagination.pageSize; - const fakeData = [...Array(amountOfFakeRows)].map( - (_, index) => index + pagination.pageIndex * pagination.pageSize, - ); - - const materialTable = useMaterialReactTable({ - // @ts-ignore - columns: reducedColumns, - data: fakeData, - rowCount: rowCount, - manualPagination: true, - // @ts-ignore - onPaginationChange: setPagination, - state: { - pagination, - }, - }); - - const loadedSchema = useExtendedSchema({ typeName, classIRI }); - const { saveMutation } = useCRUDWithQueryClient( - undefined, - undefined, - loadedSchema as JSONSchema7, - { enabled: false }, - "importsave", - undefined, - true, - ); - const handleMapAndImport = useCallback(async () => { - const rows = [...Array(pagination.pageSize)].map( - (_, index) => index + pagination.pageIndex + 2, - ); - - setRawMappedData([]); - for (const row of rows) { - const targetData = { - "@id": `${slent().value}${uuidv4()}`, - "@type": classIRI, - }; - let mappedData: any; - try { - mappedData = await mapByConfigFlat( - (col: number | string) => { - const cell = workSheet.getCell(row, col as number); - return cell.value as string; - }, - targetData, - spreadSheetMapping.mapping, - makeDefaultMappingStrategyContext( - crudOptions?.selectFetch, - declarativeMappings, - ), - ); - } catch (e) { - console.warn("failed to map row", row, e); - } - - if (mappedData) { - const success = await saveMutation.mutateAsync(mappedData); - if (success) { - console.log("success", success); - setRawMappedData((prev) => [...prev, mappedData]); - if (writeToSpreadSheet) { - const idCellColumnIndex = columnDesc.findIndex( - ({ value }) => value === "exhibition-live IRI", - ); - const directLinkCellColumnIndex = columnDesc.findIndex( - ({ value }) => value === "exhibition-live direct link", - ); - const idCell = workSheet.getCell(row, idCellColumnIndex); - const directLinkCell = workSheet.getCell( - row, - directLinkCellColumnIndex, - ); - idCell.value = mappedData["@id"]; - idCell.save(); - directLinkCell.value = `https://slub.github.io/exhibition-live/${locale}/create/${typeName}?encID=${encodeIRI( - mappedData["@id"], - )}`; - directLinkCell.save(); - } - } else { - console.error("failed"); - if (writeToSpreadSheet) { - const idCellColumnIndex = columnDesc.findIndex( - ({ value }) => value === "exhibition-live IRI", - ); - const idCell = workSheet.getCell(row, idCellColumnIndex); - idCell.value = "failed"; - idCell.save(); - } - } - } - } - //setRawMappedData(allMappedData) - }, [ - workSheet, - crudOptions, - pagination.pageSize, - pagination.pageIndex, - setRawMappedData, - locale, - spreadSheetMapping, - columnDesc, - saveMutation, - writeToSpreadSheet, - ]); - - const handleMapping = useCallback(async () => { - const rows = [...Array(pagination.pageSize)].map( - (_, index) => index + 1 + pagination.pageIndex * pagination.pageSize, - ); - const allMappedData = rawMappedData.slice(); - for (const row of rows) { - let mappedData = allMappedData.find( - (data) => data["__index"] === row - 1, - ); - if (!mappedData) { - try { - const targetData = { - __index: row - 1, - "@id": `${slent().value}${uuidv4()}`, - "@type": sladb.Exhibition.value, - }; - mappedData = await mapByConfigFlat( - (col: number | string) => { - const cell = workSheet.getCell(row, col as number); - return cell.value as string; - }, - targetData, - spreadSheetMapping.mapping, - makeDefaultMappingStrategyContext( - crudOptions?.selectFetch, - declarativeMappings, - ), - ); - allMappedData.push(mappedData); - } catch (e) { - console.warn("failed to map row", row, e); - } - } - } - setRawMappedData(allMappedData); - }, [ - workSheet, - crudOptions, - pagination.pageSize, - pagination.pageIndex, - rawMappedData, - setRawMappedData, - spreadSheetMapping, - ]); - - return loaded ? ( - - {workSheet.title} - - - { - setMaxColumns(parseInt(e.target.value)); - }} - /> - - - - - - - setWriteToSpreadSheet(e.target.checked)} - /> - } - label={"write to spreadsheet"} - /> - - - setShowTable(e.target.checked)} - /> - } - label={"show table"} - /> - - - - - - - - - - {!showTable && ( - - {columnDesc.map(({ index, value, letter }) => { - return ( - - ); - })} - - )} - {showTable && } - - - ) : ( - - ); -}; - -export type SpreadSheetViewProps = { - spreadSheet: GoogleSpreadsheet; -}; - -export const SpreadSheetView: FC = ({ spreadSheet }) => { - const [selectedSheet, setSelectedSheet] = useState(0); - - const { data: sheetsByIndexData, isLoading: sheetsByIndexLoading } = useQuery( - ["sheetsByIndex", spreadSheet.spreadsheetId], - () => { - spreadSheet.loadInfo(); - return spreadSheet.sheetsByIndex; - }, - { refetchOnWindowFocus: true }, - ); - const sheetsByIndex = useMemo(() => { - return sheetsByIndexData ?? []; - }, [sheetsByIndexData]); - - return ( - - - - {!sheetsByIndexLoading && sheetsByIndex[selectedSheet] && ( - - )} - - - setSelectedSheet(id)} - > - {sheetsByIndex.map((sheet, index) => { - return ( - - ); - })} - - - - - ), - }, - { - label: "Select Mapping", - content: ( - - Select Mapping - - ), - }, - { - label: "Select Target", - content: ( - - Select Target - - ), - }, - { - label: "Review Data", - content: ( - - Review Data - - ), - }, - ]} - /> - ); -}; - -export type SpreadSheetViewModalProps = { - sheetId: string; -}; - -export const useSpreadSheet = (sheetId: string) => { - const { credentials } = useGoogleToken(); - const spreadSheet = useMemo(() => { - const doc = new GoogleSpreadsheet(sheetId, { - token: credentials.access_token, - }); - return doc; - }, [sheetId, credentials.access_token]); - const [loaded, setLoaded] = useState(false); - useEffect(() => { - (async () => { - try { - await spreadSheet.loadInfo(); - } catch (e) { - console.error("failed to load spreadSheet", e); - setLoaded(false); - return; - } - setLoaded(true); - })(); - }, [spreadSheet, setLoaded]); - - const [title, setTitle] = useState(""); - useEffect(() => { - try { - setTitle(spreadSheet.title); - } catch (e) { - spreadSheet.loadInfo().then(() => setTitle(spreadSheet.title)); - } - }, [spreadSheet, setTitle]); - return { spreadSheet, loaded, title }; -}; -export const SpreadSheetViewModal = NiceModal.create( - ({ sheetId }: SpreadSheetViewModalProps) => { - const modal = useModal(); - const { spreadSheet, loaded, title } = useSpreadSheet(sheetId); - - return ( - modal.remove()} - fullWidth={true} - scroll={"paper"} - disableScrollLock={false} - > - - - - {loaded ? title : "loading Spreadsheet ..."} - - - - modal.remove()} - color="inherit" - > - - - - - - - {loaded ? ( - - ) : ( - - )} - - - - - - ); - }, -); - -type GoogleSpreadSheetViewProps = { - sheetId: string; -}; -export const GoogleSpreadSheetView: FC = ({ - sheetId, -}) => { - const { spreadSheet, loaded } = useSpreadSheet(sheetId); - return loaded && ; -}; diff --git a/apps/exhibition-live/components/google/SpreadSheetWorkSheetView.tsx b/apps/exhibition-live/components/google/SpreadSheetWorkSheetView.tsx new file mode 100644 index 00000000..96ceab08 --- /dev/null +++ b/apps/exhibition-live/components/google/SpreadSheetWorkSheetView.tsx @@ -0,0 +1,473 @@ +import React, { useCallback, useEffect, useMemo, useState } from "react"; +import { + useAdbContext, + useCRUDWithQueryClient, + useExtendedSchema, + useGlobalCRUDOptions, + useModifiedRouter, +} from "@slub/edb-state-hooks"; +import { + CellTypeLike, + LoadableWorkSheet, + useCashedWorkSheet, +} from "./useCachedWorkSheet"; +import { + MaterialReactTable, + MRT_ColumnDef, + useMaterialReactTable, +} from "material-react-table"; +import { OwnColumnDesc } from "./types"; +import { + DeclarativeFlatMappings, + DeclarativeMatchBasedFlatMappings, + mapByConfigFlat, +} from "@slub/edb-data-mapping"; +import { spreadSheetMappings } from "../config/spreadSheetMappings"; +import { MappedItem } from "./MappedItem"; +import { + Box, + Button, + Checkbox, + FormControl, + Grid, + MenuItem, + Select, + Skeleton, + TextField, + Typography, +} from "@mui/material"; +import FormControlLabel from "@mui/material/FormControlLabel"; +import { ColumnChip } from "./ColumnChip"; +import { filterUndefOrNull, index2letter } from "@slub/edb-core-utils"; +import { makeDefaultMappingStrategyContext } from "@slub/edb-ui-utils"; + +export type SpreadSheetWorkSheetViewProps< + CellType extends CellTypeLike, + RemoteWorksheet extends LoadableWorkSheet, +> = { + workSheet: RemoteWorksheet; + mappingId: string; +}; +export const SpreadSheetWorkSheetView = < + CellType extends CellTypeLike, + RemoteWorksheet extends LoadableWorkSheet, +>({ + workSheet: workSheetOriginal, + mappingId, +}: SpreadSheetWorkSheetViewProps) => { + const { + queryBuildOptions: { prefixes, primaryFields }, + typeNameToTypeIRI, + typeIRIToTypeName, + createEntityIRI, + jsonLDConfig: { defaultPrefix }, + normDataMapping, + } = useAdbContext(); + const workSheet = useCashedWorkSheet({ + workSheet: workSheetOriginal, + autoCache: true, + }); + const loaded = workSheet.loaded; + const [_loaded, setLoaded] = useState(false); + const [pagination, setPagination] = useState({ + pageIndex: 0, + pageSize: 5, + }); + const [columns, setColumns] = useState[]>([]); + const [reducedColumns, setReducedColumns] = useState[]>( + [], + ); + const [maxColumns, setMaxColumns] = useState(10); + const [showTable, setShowTable] = useState(false); + const [columnDesc, setColumnDesc] = useState([]); + const [writeToSpreadSheet, setWriteToSpreadSheet] = useState(false); + + const [rawMappedData, setRawMappedData] = useState([]); + const { + query: { locale = "de" }, + } = useModifiedRouter(); + const selectedMapping = useMemo( + () => spreadSheetMappings[mappingId], + [mappingId], + ); + + const { crudOptions } = useGlobalCRUDOptions(); + const spreadSheetMapping = useMemo(() => { + let final: { + raw?: DeclarativeMatchBasedFlatMappings; + mapping: DeclarativeFlatMappings; + } = { + mapping: [], + }; + try { + const cSpreadSheetMapping = selectedMapping; + final = + columnDesc.length <= 0 || !cSpreadSheetMapping + ? final + : { + raw: cSpreadSheetMapping.raw, + mapping: cSpreadSheetMapping.fieldMapping(columnDesc), + }; + } catch (e) { + console.error( + "failed to apply declarative mapping to column description", + e, + ); + } + return final; + }, [columnDesc, selectedMapping]); + + useEffect(() => { + setReducedColumns(columns?.slice(0, maxColumns) || []); + }, [columns, maxColumns, setReducedColumns]); + + const calculateMapping = useCallback(async () => { + if (!workSheet.loaded) return; + try { + //first get the header cells to get the column names + const headerCells = [...Array(workSheet.columnCount)].map((_, index) => { + return workSheet.getCell(0, index); + }); + const columnDesc_ = headerCells.map((googleSpreadSheetCell, index) => ({ + index, + value: googleSpreadSheetCell?.value || null, + letter: index2letter(index), + })); + setColumnDesc(columnDesc_); + const cols = headerCells.map((cell, index) => { + return { + id: (cell.value ?? "").toString() + index, + header: (cell.value ?? "").toString(), + accessorFn: (originalRow, rowIndex) => { + try { + const dataCell = workSheet.getCell(originalRow + 1, index); + return dataCell?.value ?? null; + } catch (e) { + return null; + } + }, + }; + }); + setColumns(cols as MRT_ColumnDef[]); + } catch (e) { + console.log(e); + } + setLoaded(true); + }, [ + workSheet, + crudOptions, + spreadSheetMapping.mapping, + setLoaded, + setColumnDesc, + ]); + + useEffect(() => { + if (!loaded) return; + calculateMapping(); + }, [loaded]); + + useEffect(() => { + if (spreadSheetMapping.mapping.length <= 0) return; + const mappedCol = { + id: "-1", + header: "mapped Data", + accessorFn: (originalRow, rowIndex) => { + return originalRow + 1; + }, + Cell: ({ cell }) => { + const rowIndex = cell.getValue(); + const pathSegments = [ + workSheet.sheetId, + String(workSheet.index), + String(rowIndex), + ]; + + return ( + <> + + + ); + }, + }; + // @ts-ignore + setColumns((prev) => [mappedCol, ...prev.filter((col) => col.id !== "-1")]); + }, [workSheet, crudOptions, spreadSheetMapping.mapping, setColumns]); + + const rowCount = useMemo( + () => Math.ceil(workSheet.rowCount - 2), + [workSheet.rowCount], + ); + // needs to be just the right amount of rows: so full pageSize but a the end the Rest of the rowCount divided by pageSize + const isLastRow = rowCount - 2 <= pagination.pageSize * pagination.pageIndex; + const amountOfFakeRows = + rowCount <= 0 + ? 0 + : isLastRow + ? rowCount % pagination.pageSize + : pagination.pageSize; + const fakeData = [...Array(amountOfFakeRows)].map( + (_, index) => index + pagination.pageIndex * pagination.pageSize, + ); + + const materialTable = useMaterialReactTable({ + // @ts-ignore + columns: reducedColumns, + data: fakeData, + rowCount: rowCount, + manualPagination: true, + // @ts-ignore + onPaginationChange: setPagination, + state: { + pagination, + }, + }); + + const typeName = "Exhibition"; + const classIRI = useMemo( + () => typeNameToTypeIRI(typeName), + [typeName, typeNameToTypeIRI], + ); + const loadedSchema = useExtendedSchema({ typeName }); + const { saveMutation } = useCRUDWithQueryClient({ + schema: loadedSchema, + queryOptions: { enabled: false }, + loadQueryKey: "importsave", + allowUnsafeSourceIRIs: true, + }); + const handleMapAndImport = useCallback(async () => { + const rows = [...Array(pagination.pageSize)].map( + (_, index) => index + pagination.pageIndex * pagination.pageSize + 1, + ); + console.log({ rows }); + + setRawMappedData([]); + for (const row of rows) { + const targetData = { + "@id": createEntityIRI(typeName), + "@type": classIRI, + }; + let mappedData: any; + try { + mappedData = await mapByConfigFlat( + (col: number | string) => { + const cell = workSheet.getCell(row, col as number); + return cell.value as string; + }, + targetData, + spreadSheetMapping.mapping, + makeDefaultMappingStrategyContext( + crudOptions?.selectFetch, + { + defaultPrefix, + prefixes, + }, + createEntityIRI, + typeIRIToTypeName, + primaryFields, + normDataMapping, + ), + ); + } catch (e) { + console.warn("failed to map row", row, e); + } + console.log({ mappedData }); + + if (mappedData) { + const success = await saveMutation.mutateAsync(mappedData); + if (success) { + console.log("success", success); + setRawMappedData((prev) => [...prev, mappedData]); + /*if (writeToSpreadSheet) { + const idCellColumnIndex = columnDesc.findIndex( + ({value}) => value === "exhibition-live IRI", + ); + const directLinkCellColumnIndex = columnDesc.findIndex( + ({value}) => value === "exhibition-live direct link", + ); + const idCell = workSheet.getCell(row, idCellColumnIndex); + const directLinkCell = workSheet.getCell( + row, + directLinkCellColumnIndex, + ); + idCell.value = mappedData["@id"]; + idCell.save(); + directLinkCell.value = `https://slub.github.io/exhibition-live/${locale}/create/${typeName}?encID=${encodeIRI( + mappedData["@id"], + )}`; + directLinkCell.save(); + }*/ + } else { + console.error("failed"); + /*if (writeToSpreadSheet) { + const idCellColumnIndex = columnDesc.findIndex( + ({value}) => value === "exhibition-live IRI", + ); + const idCell = workSheet.getCell(row, idCellColumnIndex); + idCell.value = "failed"; + idCell.save(); + }*/ + } + } + } + //setRawMappedData(allMappedData) + }, [ + workSheet, + crudOptions, + pagination.pageSize, + pagination.pageIndex, + setRawMappedData, + locale, + spreadSheetMapping, + columnDesc, + saveMutation, + writeToSpreadSheet, + typeName, + classIRI, + createEntityIRI, + defaultPrefix, + prefixes, + typeIRIToTypeName, + primaryFields, + normDataMapping, + ]); + + const handleMapping = useCallback(async () => { + const rows = [...Array(pagination.pageSize)].map( + (_, index) => index + 1 + pagination.pageIndex * pagination.pageSize, + ); + const allMappedData = rawMappedData.slice(); + for (const row of rows) { + let mappedData = allMappedData.find( + (data) => data["__index"] === row - 1, + ); + if (!mappedData) { + try { + const targetData = { + __index: row - 1, + "@id": createEntityIRI(typeName), + "@type": classIRI, + }; + mappedData = await mapByConfigFlat( + (col: number | string) => { + const cell = workSheet.getCell(row, col as number); + return cell.value as string; + }, + targetData, + spreadSheetMapping.mapping, + makeDefaultMappingStrategyContext( + crudOptions?.selectFetch, + { + defaultPrefix, + prefixes, + }, + createEntityIRI, + typeNameToTypeIRI, + primaryFields, + normDataMapping, + ), + ); + allMappedData.push(mappedData); + } catch (e) { + console.warn("failed to map row", row, e); + } + } + } + setRawMappedData(allMappedData); + }, [ + workSheet, + crudOptions, + pagination.pageSize, + pagination.pageIndex, + rawMappedData, + setRawMappedData, + spreadSheetMapping, + classIRI, + createEntityIRI, + defaultPrefix, + prefixes, + primaryFields, + normDataMapping, + ]); + + return loaded ? ( + + {workSheet.title} + + + { + setMaxColumns(parseInt(e.target.value)); + }} + /> + + + + setWriteToSpreadSheet(e.target.checked)} + /> + } + label={"write to spreadsheet"} + /> + + + setShowTable(e.target.checked)} + /> + } + label={"show table"} + /> + + + + + + + + + + {!showTable && ( + + {columnDesc.map(({ index, value, letter }) => { + return ( + + ); + })} + + )} + {showTable && } + + + ) : ( + + ); +}; diff --git a/apps/exhibition-live/components/google/mappingsAvailable.ts b/apps/exhibition-live/components/google/mappingsAvailable.ts new file mode 100644 index 00000000..d402e7f1 --- /dev/null +++ b/apps/exhibition-live/components/google/mappingsAvailable.ts @@ -0,0 +1,3 @@ +import { spreadSheetMappings } from "../config/spreadSheetMappings"; + +export const mappingsAvailable = Object.keys(spreadSheetMappings); diff --git a/apps/exhibition-live/components/google/types.ts b/apps/exhibition-live/components/google/types.ts index 0019c405..985e06d6 100644 --- a/apps/exhibition-live/components/google/types.ts +++ b/apps/exhibition-live/components/google/types.ts @@ -1,7 +1,40 @@ -import { GoogleSpreadsheetCellErrorValue } from "google-spreadsheet"; +import { ColumnDesc } from "@slub/edb-core-types"; -export type OwnColumnDesc = { - index: number; - value: string | number | null | boolean | GoogleSpreadsheetCellErrorValue; - letter: string; +type ErrorValue = { + type: CellValueErrorType; + message: string; }; + +type CellValueErrorType = + /** Corresponds to the #ERROR! error */ + | "ERROR" + /** Corresponds to the #NULL! error. */ + | "NULL_VALUE" + /** Corresponds to the #DIV/0 error. */ + | "DIVIDE_BY_ZERO" + /** Corresponds to the #VALUE! error. */ + | "VALUE" + /** Corresponds to the #REF! error. */ + | "REF" + /** Corresponds to the #NAME? error. */ + | "NAME" + /** Corresponds to the #NUM! error. */ + | "NUM" + /** Corresponds to the #N/A error. */ + | "N_A" + /** Corresponds to the Loading... state. */ + | "LOADING"; +declare class GoogleSpreadsheetCellErrorValue { + /** + * type of the error + * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/other#ErrorType + * */ + readonly type: CellValueErrorType; + /** A message with more information about the error (in the spreadsheet's locale) */ + readonly message: string; + constructor(rawError: ErrorValue); +} + +export type OwnColumnDesc = ColumnDesc< + string | number | null | boolean | GoogleSpreadsheetCellErrorValue +>; diff --git a/apps/exhibition-live/components/google/useCachedWorkSheet.ts b/apps/exhibition-live/components/google/useCachedWorkSheet.ts new file mode 100644 index 00000000..96be2337 --- /dev/null +++ b/apps/exhibition-live/components/google/useCachedWorkSheet.ts @@ -0,0 +1,136 @@ +import { useCallback, useEffect, useState } from "react"; + +export type CellTypeLike = { + value: string | number | boolean | null | any; +}; + +export type WorkSheet = { + title: string; + sheetId: number; + index: number; + rowCount: number; + columnCount: number; + getCell: (rowIndex: number, columnIndex: number) => CellType | null; +}; + +export type CachedWorkSheet = + WorkSheet & { + loaded: boolean; + preloadCells: ( + startRowIndex?: number, + endRowIndex?: number, + startColumnIndex?: number, + endColumnIndex?: number, + ) => Promise; + }; + +export type LoadableWorkSheet = + WorkSheet & { + loadCells: (options: { + startRowIndex: number; + endRowIndex: number; + startColumnIndex: number; + endColumnIndex: number; + }) => Promise; + }; + +export type UseCachedWorkSheetOptions< + CellType extends CellTypeLike, + RemoteWorkSheet = WorkSheet, +> = { + workSheet: RemoteWorkSheet; + staleTime?: number; + autoCache?: boolean; +}; +export const useCashedWorkSheet = < + CellType extends CellTypeLike, + RemoteWorksheet extends LoadableWorkSheet, +>({ + workSheet, + staleTime = 1000 * 60 * 5, + autoCache, +}: UseCachedWorkSheetOptions< + CellType, + RemoteWorksheet +>): CachedWorkSheet => { + const [loaded, setLoaded] = useState(false); + const [rowCount, setRowCount] = useState(0); + const [columnCount, setColumnCount] = useState(0); + const [title, setTitle] = useState(""); + + const getCell = useCallback( + (rowIndex: number, columnIndex: number) => { + try { + return workSheet.getCell(rowIndex, columnIndex); + } catch (e) { + console.error("failed to load cell", e); + return null; + } + }, + [workSheet], + ); + + const preloadCells = useCallback( + async ( + startRowIndex = 0, + endRowIndex = 10, + startColumnIndex = 0, + endColumnIndex = 10, + ) => { + console.log("will load cells", { + startRowIndex, + endRowIndex, + startColumnIndex, + endColumnIndex, + }); + try { + await workSheet.loadCells({ + startRowIndex, + endRowIndex, + startColumnIndex, + endColumnIndex, + }); + } catch (e) { + console.error("failed to load cells", e); + setTimeout(() => { + console.log("retrying to load cells"); + setLoaded(true); + }, 1); + return; + } + setLoaded(true); + }, + [workSheet, setLoaded], + ); + + useEffect(() => { + (async () => { + setRowCount(workSheet.rowCount); + setColumnCount(workSheet.columnCount); + setTitle(workSheet.title); + })(); + }, [workSheet, setLoaded, setRowCount, setColumnCount, setTitle]); + + useEffect(() => { + if (autoCache && !loaded) { + preloadCells(0, workSheet.rowCount, 0, workSheet.columnCount); + } + }, [ + workSheet.rowCount, + workSheet.columnCount, + autoCache, + loaded, + preloadCells, + ]); + + return { + loaded, + title, + sheetId: workSheet.sheetId, + index: workSheet.index, + rowCount, + columnCount, + preloadCells, + getCell, + }; +}; diff --git a/apps/exhibition-live/components/google/useGoogleSpreadSheet.ts b/apps/exhibition-live/components/google/useGoogleSpreadSheet.ts new file mode 100644 index 00000000..e4a384c8 --- /dev/null +++ b/apps/exhibition-live/components/google/useGoogleSpreadSheet.ts @@ -0,0 +1,55 @@ +import { useGoogleToken } from "./useGoogleToken"; +import { useEffect, useMemo, useState } from "react"; +import { + GoogleSpreadsheet, + GoogleSpreadsheetWorksheet, +} from "google-spreadsheet"; +import { useQuery } from "@slub/edb-state-hooks"; + +export const useGoogleSpreadSheet: (sheetId: string) => { + loaded: boolean; + sheetsByIndex: GoogleSpreadsheetWorksheet[]; + sheetsById: Record; + title: string; + spreadSheet: GoogleSpreadsheet; +} = (sheetId: string) => { + const { credentials } = useGoogleToken(); + const spreadSheet = useMemo(() => { + const doc = new GoogleSpreadsheet(sheetId, { + token: credentials.access_token, + }); + return doc; + }, [sheetId, credentials.access_token]); + const [loaded, setLoaded] = useState(false); + const { data: sheetsData, isLoading: sheetsByIndexLoading } = useQuery( + ["sheetsByIndex", spreadSheet.spreadsheetId], + async () => { + try { + await spreadSheet.loadInfo(); + } catch (e) { + console.error("failed to load spreadSheet", e); + setLoaded(false); + return; + } + setLoaded(true); + return spreadSheet; + }, + { refetchOnWindowFocus: true }, + ); + + const [title, setTitle] = useState(""); + useEffect(() => { + try { + setTitle(spreadSheet.title); + } catch (e) { + spreadSheet.loadInfo().then(() => setTitle(spreadSheet.title)); + } + }, [spreadSheet, setTitle]); + return { + spreadSheet, + sheetsByIndex: sheetsData?.sheetsByIndex, + sheetsById: sheetsData?.sheetsById, + loaded, + title, + }; +}; diff --git a/apps/exhibition-live/components/graphql/queries.graphql.ts b/apps/exhibition-live/components/graphql/queries.graphql.ts deleted file mode 100644 index 68f72b6d..00000000 --- a/apps/exhibition-live/components/graphql/queries.graphql.ts +++ /dev/null @@ -1,62 +0,0 @@ -import gql from "graphql-tag"; - -export const allExhibitions = gql` - query allExhibitions { - getExhibitions { - id - title - description - fromDate - toDate - places { - title - location { - id - title - } - } - locations { - id - title - } - weblink - } - } -`; - -export const searchExhibitions = gql` - query searchExhibitions($searchString: String) { - getExhibitions(filters: { title: { iContains: $searchString } }) { - id - title - description - fromDate - toDate - places { - title - location { - id - title - } - } - locations { - id - title - } - weblink - } - } -`; - -export const searchPersons = gql` - query allPersons { - getPersons { - id - nameVariants - name - description - gender - normdata - } - } -`; diff --git a/apps/exhibition-live/components/graphql/useFetchData.ts b/apps/exhibition-live/components/graphql/useFetchData.ts deleted file mode 100644 index 0c19d166..00000000 --- a/apps/exhibition-live/components/graphql/useFetchData.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { API_URL } from "../config"; - -export const fetchData: ( - body: string, - headers?: HeadersInit, -) => Promise = async (body: string, headers = {}) => { - const res = await fetch(API_URL, { - method: "POST", - headers: { - "Content-Type": "application/json", - ...headers, - }, - body, - }); - - const json = await res.json(); - - if (json.errors) { - const { message } = json.errors[0] || "Error.."; - throw new Error(message); - } - - return json.data as TData; -}; - -export const useFetchData = ( - query: string, -): (() => Promise) => { - // it is safe to call React Hooks here. - return async (variables?: TVariables) => - await fetchData(JSON.stringify({ query, variables })); -}; diff --git a/apps/exhibition-live/components/i18n/Redirect.tsx b/apps/exhibition-live/components/i18n/Redirect.tsx index dde5a07e..7eb2d726 100644 --- a/apps/exhibition-live/components/i18n/Redirect.tsx +++ b/apps/exhibition-live/components/i18n/Redirect.tsx @@ -1,17 +1,17 @@ import { useEffect } from "react"; -import { useRouter } from "next/router"; import languageDetector from "./languageDetector"; +import { useModifiedRouter } from "@slub/edb-state-hooks"; export const useRedirect = (to?: string) => { - const router = useRouter(); + const router = useModifiedRouter(); to = to || router.asPath; // language detection useEffect(() => { const detectedLng = languageDetector.detect(); - if (to.startsWith("/" + detectedLng) && router.route === "/404") { + if (to.startsWith("/" + detectedLng) && router.asPath === "/404") { // prevent endless loop - router.replace("/" + detectedLng + router.route); + router.replace("/" + detectedLng + router.asPath); return; } diff --git a/apps/exhibition-live/components/importExport/ImportPage.tsx b/apps/exhibition-live/components/importExport/ImportPage.tsx index d581b75e..b5b35529 100644 --- a/apps/exhibition-live/components/importExport/ImportPage.tsx +++ b/apps/exhibition-live/components/importExport/ImportPage.tsx @@ -1,13 +1,13 @@ -import React, { FunctionComponent, useCallback } from "react"; +import React, { FunctionComponent, useCallback, useMemo } from "react"; import { Box, Button } from "@mui/material"; import Grid2 from "@mui/material/Unstable_Grid2"; import { Login } from "../google/GoogleOAuth"; -import { useModifiedRouter } from "../basic"; -import { hasGrantedAnyScopeGoogle } from "@react-oauth/google"; import { useGoogleToken } from "../google/useGoogleToken"; import NiceModal from "@ebay/nice-modal-react"; import { GoogleDrivePickerModal } from "../google/GoogleDrivePicker"; -import { GoogleSpreadSheetView } from "../google/SpreadSheetView"; +import { useModifiedRouter } from "@slub/edb-state-hooks"; +import { GoogleSpreadSheetContainer } from "../google/GoogleSpreadSheetContainer"; +import { hasGrantedAnyScopeGoogle, useGoogleOAuth } from "@react-oauth/google"; const scopes: [string, string, string] = [ "https://www.googleapis.com/auth/drive.readonly.metadata", @@ -16,16 +16,49 @@ const scopes: [string, string, string] = [ ]; export const ImportPage: FunctionComponent = () => { const { credentials } = useGoogleToken(); + const { clientId } = useGoogleOAuth(); const router = useModifiedRouter(); - const { documentId } = router.query; + const documentId = useMemo( + () => router.searchParams.get("documentId"), + [router.searchParams], + ); + const sheetId = useMemo(() => { + const _id = Number(router.searchParams.get("sheetId")); + if (isNaN(_id)) { + return undefined; + } + return _id; + }, [router.searchParams]); + const mappingId = useMemo( + () => router.searchParams.get("mappingId"), + [router.searchParams], + ); - const hasAccess = - credentials && hasGrantedAnyScopeGoogle(credentials, ...scopes); + const hasAccess = useMemo(() => { + if (!clientId) { + return false; + } + const granted = + typeof window !== "undefined" && + hasGrantedAnyScopeGoogle(credentials, ...scopes); + return Boolean(credentials) && granted; + }, [credentials, clientId]); const openDrivePicker = useCallback(() => { - NiceModal.show(GoogleDrivePickerModal, {}).then((documentId: string) => { - console.log(documentId); - router.push(`/import?documentId=${documentId}`); - }); + NiceModal.show(GoogleDrivePickerModal, {}).then( + ({ + documentId, + sheetId, + mappingId, + }: { + documentId: string; + sheetId: number; + mappingId: string; + }) => { + router.push( + `/import?documentId=${documentId}&sheetId=${sheetId}&mappingId=${mappingId}`, + ); + }, + ); }, [router]); return ( { spacing={3} sx={{ p: { md: 10 } }} > + {clientId && ( + + + {hasAccess && ( + + )} + + )} - - {hasAccess && } - - - {hasAccess && typeof documentId === "string" && ( - - )} + {hasAccess && + typeof documentId === "string" && + typeof sheetId === "number" && + typeof mappingId === "string" && ( + + )} diff --git a/apps/exhibition-live/components/layout/PerformanceHeader.tsx b/apps/exhibition-live/components/layout/PerformanceHeader.tsx index c68e71cc..a445d22d 100644 --- a/apps/exhibition-live/components/layout/PerformanceHeader.tsx +++ b/apps/exhibition-live/components/layout/PerformanceHeader.tsx @@ -3,8 +3,7 @@ import { Button, Grid } from "@mui/material"; import React, { FunctionComponent } from "react"; import SettingsModal from "../content/settings/SettingsModal"; -import { useLocalSettings } from "../state/useLocalSettings"; -import { Img } from "../utils/image/Img"; +import { useLocalSettings } from "@slub/edb-state-hooks"; import { Logo } from "./main-layout"; interface OwnProps {} diff --git a/apps/exhibition-live/components/layout/main-layout/AppHeader.tsx b/apps/exhibition-live/components/layout/main-layout/AppHeader.tsx index 9b261764..a0d1bcc9 100644 --- a/apps/exhibition-live/components/layout/main-layout/AppHeader.tsx +++ b/apps/exhibition-live/components/layout/main-layout/AppHeader.tsx @@ -1,18 +1,8 @@ // material-ui import MenuIcon from "@mui/icons-material/Menu"; import ListIcon from "@mui/icons-material/List"; -import { - ButtonBase, - useTheme, - AppBar, - Toolbar, - Button, - Hidden, - ToggleButton, -} from "@mui/material"; +import { ButtonBase, useTheme, AppBar, Toolbar } from "@mui/material"; import React from "react"; -import { useFormEditor } from "../../state"; -import { useSettings } from "../../state/useLocalSettings"; type AppHeaderProps = { toggleDrawer: () => void; diff --git a/apps/exhibition-live/components/layout/main-layout/Logo.tsx b/apps/exhibition-live/components/layout/main-layout/Logo.tsx index 2b143866..a869c7f2 100644 --- a/apps/exhibition-live/components/layout/main-layout/Logo.tsx +++ b/apps/exhibition-live/components/layout/main-layout/Logo.tsx @@ -1,7 +1,6 @@ import { ImageProps } from "next/image"; import React from "react"; - -import { Img } from "../../utils/image/Img"; +import { Img } from "../../basic"; type OwnProps = { size?: number; diff --git a/apps/exhibition-live/components/layout/main-layout/MainLayout.stories.tsx b/apps/exhibition-live/components/layout/main-layout/MainLayout.stories.tsx index 679c5fc8..544fe776 100644 --- a/apps/exhibition-live/components/layout/main-layout/MainLayout.stories.tsx +++ b/apps/exhibition-live/components/layout/main-layout/MainLayout.stories.tsx @@ -3,11 +3,11 @@ import React, { useMemo } from "react"; import { MainLayout } from "./MainLayout"; import TypedForm from "../../content/main/TypedFormNoSSR"; -import { sladb, slent } from "../../form/formConfigs"; -import { QueryClientProvider, QueryClient } from "@tanstack/react-query"; +import { sladb, slent } from "../../config/formConfigs"; +import { QueryClientProvider, QueryClient } from "@slub/edb-state-hooks"; export default { - title: "layout/MainLayout", + title: "ui/layout/MainLayout", component: MainLayout, } as Meta; diff --git a/apps/exhibition-live/components/layout/main-layout/MainLayout.tsx b/apps/exhibition-live/components/layout/main-layout/MainLayout.tsx index ac88ad72..97ed576e 100644 --- a/apps/exhibition-live/components/layout/main-layout/MainLayout.tsx +++ b/apps/exhibition-live/components/layout/main-layout/MainLayout.tsx @@ -1,20 +1,8 @@ -// assets -import { ChevronRight as IconChevronRight } from "@mui/icons-material"; -import { - AppBar, - Box, - CssBaseline, - styled, - Theme, - Toolbar, - useMediaQuery, - useTheme, -} from "@mui/material"; +import { Box, CssBaseline, styled, Theme, useTheme } from "@mui/material"; import { useCallback, useState } from "react"; import { AppHeader } from "./AppHeader"; import { Sidebar } from "./Sidebar"; -import { useDrawerDimensions } from "../../state"; export const gridSpacing = 3; export const leftDrawerWidth = 260; @@ -27,7 +15,6 @@ type MainProps = { const Main = styled("main", { shouldForwardProp: (prop) => prop !== "open" && prop !== "theme", })(({ theme }: MainProps) => { - const { drawerHeight } = useDrawerDimensions(); return { // @ts-ignore ...theme.typography.mainContent, diff --git a/apps/exhibition-live/components/layout/main-layout/SearchSection.tsx b/apps/exhibition-live/components/layout/main-layout/SearchSection.tsx index 79f426bf..65091bbe 100644 --- a/apps/exhibition-live/components/layout/main-layout/SearchSection.tsx +++ b/apps/exhibition-live/components/layout/main-layout/SearchSection.tsx @@ -3,16 +3,18 @@ import { Avatar, OutlinedInput, Popper } from "@mui/material"; import { styled } from "@mui/material/styles"; import { shouldForwardProp } from "@mui/system"; // assets -import React, { useCallback } from "react"; +import React, { useCallback, useMemo } from "react"; import { useTranslation } from "next-i18next"; // third-party // project imports -import DiscoverAutocompleteInput from "../../form/discover/DiscoverAutocompleteInput"; -import { sladb } from "../../form/formConfigs"; -import { useGlobalSearch } from "../../state"; -import { encodeIRI } from "../../utils/core"; -import { useModifiedRouter } from "../../basic"; +import { + useAdbContext, + useGlobalSearch, + useModifiedRouter, +} from "@slub/edb-state-hooks"; +import { encodeIRI } from "@slub/edb-ui-utils"; +import { DiscoverAutocompleteInput } from "@slub/edb-advanced-components"; // styles const PopperStyle = styled(Popper, { shouldForwardProp })(({ theme }) => ({ @@ -67,9 +69,13 @@ export const SearchSection = () => { const { t } = useTranslation(); const { search, setSearch } = useGlobalSearch(); const router = useModifiedRouter(); + const { typeNameToTypeIRI } = useAdbContext(); const { typeName } = router.query as { typeName: string | null | undefined }; - const classIRI: string | undefined = - typeof typeName === "string" ? sladb(typeName).value : undefined; + const classIRI: string | undefined = useMemo( + () => + typeof typeName === "string" ? typeNameToTypeIRI(typeName) : undefined, + [typeName, typeNameToTypeIRI], + ); const handleChange = useCallback( (value?: string | null) => { diff --git a/apps/exhibition-live/components/layout/main-layout/Searchbar.tsx b/apps/exhibition-live/components/layout/main-layout/Searchbar.tsx deleted file mode 100644 index 4552effb..00000000 --- a/apps/exhibition-live/components/layout/main-layout/Searchbar.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { Box, Toolbar } from "@mui/material"; -import React, { useCallback, useState } from "react"; -import { FloatingButton } from "./menu"; -import MuiDrawer from "@mui/material/Drawer"; -import { useRightDrawerState } from "../../state"; - -type SearchbarProps = { - drawerWidth: number; - open: boolean; -} & SearchbarWithFloatingButtonProps; - -export const Searchbar = ({ open, drawerWidth, children }: SearchbarProps) => { - try { - return ( - - - - {children} - - - ); - } catch (e) { - console.error(e); - return null; - } -}; - -type SearchbarWithFloatingButtonProps = { - children?: React.ReactNode; -}; - -export const SearchbarWithFloatingButton = ({ - children, -}: SearchbarWithFloatingButtonProps) => { - const { - open: rightDrawerOpened, - setOpen: setRightDrawerOpened, - width: rightDrawerWidth, - setWidth: setRightDrawerWidth, - } = useRightDrawerState(); - const toggleRightDrawer = useCallback(() => { - setRightDrawerOpened((prev: boolean) => !prev); - }, [setRightDrawerOpened]); - return ( - <> - - - {rightDrawerOpened && children ? children : null} - - - ); -}; diff --git a/apps/exhibition-live/components/layout/main-layout/Sidebar.tsx b/apps/exhibition-live/components/layout/main-layout/Sidebar.tsx index 19255521..31e3aefa 100644 --- a/apps/exhibition-live/components/layout/main-layout/Sidebar.tsx +++ b/apps/exhibition-live/components/layout/main-layout/Sidebar.tsx @@ -1,16 +1,18 @@ import { ImportExport, Settings } from "@mui/icons-material"; import { useMediaQuery, useTheme, List, Divider, Toolbar } from "@mui/material"; -import { JSONSchema7 } from "json-schema"; import React, { useCallback, useMemo } from "react"; -import loadedSchema from "../../../public/schema/Exhibition.schema.json"; import SettingsModal from "../../content/settings/SettingsModal"; -import { useLocalSettings } from "../../state/useLocalSettings"; -import { MenuGroup, NavGroup, NavItem, Drawer } from "./menu"; -import menuLists from "./menu/menuLists"; -import { useGlobalAuth } from "../../state"; +import { + useAdbContext, + useLocalSettings, + useModifiedRouter, +} from "@slub/edb-state-hooks"; +import { Drawer } from "./menu"; import { useTranslation } from "next-i18next"; -import { useModifiedRouter } from "../../basic"; +import { useGlobalAuth } from "../../state/useGlobalAuth"; +import { createMenuListFromSchema } from "./createMenuListFromSchema"; +import { MenuGroup, NavGroup, NavItem } from "@slub/edb-advanced-components"; type SidebarProps = { open?: boolean; @@ -69,11 +71,10 @@ const Options = ({ open }) => { const Navigation = ({ open }) => { const { t } = useTranslation(); const { getPermission } = useGlobalAuth(); + const { schema } = useAdbContext(); const menuGroup = useMemo(() => { - return loadedSchema - ? menuLists(loadedSchema as JSONSchema7, getPermission, t) - : (null as MenuGroup); - }, [getPermission, t]); + return schema ? createMenuListFromSchema(schema, getPermission, t) : null; + }, [schema, getPermission, t]); return ( menuGroup && ( <> @@ -98,7 +99,6 @@ export const Sidebar = ({ open, onClose }: SidebarProps) => { > - diff --git a/apps/exhibition-live/components/layout/main-layout/createMenuListFromSchema.ts b/apps/exhibition-live/components/layout/main-layout/createMenuListFromSchema.ts new file mode 100644 index 00000000..44462402 --- /dev/null +++ b/apps/exhibition-live/components/layout/main-layout/createMenuListFromSchema.ts @@ -0,0 +1,76 @@ +import { + Face as IconFaceId, + FormatPaint as IconPaint, + Theaters as IconDots, + CorporateFare as IconCorporation, +} from "@mui/icons-material"; +import { JSONSchema7 } from "json-schema"; + +import { TFunction } from "i18next"; +import { Permission } from "@slub/edb-core-types"; +import { MenuGroup, MenuItem } from "@slub/edb-advanced-components"; + +const icons = { IconFaceId, IconPaint, IconDots, IconCorporation }; + +const icon2Type = { + Exhibition: "IconFaceId", + Person: "IconPaint", + Corporation: "IconCorporation", +}; + +const topLevel = ["Exhibition", "Person"]; +const disabledTypes = [ + "InvolvedPerson", + "InvolvedCorporation", + "ExponatsAndPersons", + "ExponatsAndCorporations", + "Workplace", +]; + +const iconFromType = (type: string) => { + return icon2Type[type] ? icons[icon2Type[type]] : null; +}; + +const withIcon = (type: string) => { + const icon = iconFromType(type); + return icon ? { icon } : {}; +}; + +export const createMenuListFromSchema: ( + schema: JSONSchema7, + getPermission: (typeName: string) => Permission, + t: TFunction, +) => MenuGroup = (exhibitionSchema, getPermission, t) => ({ + id: "lists", + type: "group", + children: [ + ...topLevel.map( + (key) => + ({ + id: `list_${key}`, + title: t(key), + type: "item", + typeName: key, + readOnly: !getPermission(key).edit, + ...withIcon(key), + }) as MenuItem, + ), + ...Object.entries( + exhibitionSchema.definitions || exhibitionSchema["$defs"] || {}, + ) + .filter( + ([key]) => !topLevel.includes(key) && disabledTypes.indexOf(key) === -1, + ) + .map( + ([key, value]) => + ({ + id: `list_${key}`, + title: t(key), + type: "item", + typeName: key, + readOnly: !getPermission(key).edit, + ...withIcon(key), + }) as MenuItem, + ), + ], +}); diff --git a/apps/exhibition-live/components/layout/main-layout/menu/index.ts b/apps/exhibition-live/components/layout/main-layout/menu/index.ts index 95ba8e22..2ce290b6 100644 --- a/apps/exhibition-live/components/layout/main-layout/menu/index.ts +++ b/apps/exhibition-live/components/layout/main-layout/menu/index.ts @@ -1,7 +1 @@ -export * from "./menuLists"; -export * from "./NavCollapse"; -export * from "./NavGroup"; -export * from "./NavItem"; -export * from "./types"; export * from "./Drawer"; -export * from "./FloatingButton"; diff --git a/apps/exhibition-live/components/layout/main-layout/menu/menuLists.ts b/apps/exhibition-live/components/layout/main-layout/menu/menuLists.ts deleted file mode 100644 index e4ae9748..00000000 --- a/apps/exhibition-live/components/layout/main-layout/menu/menuLists.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { - Face as IconFaceId, - FormatPaint as IconPaint, - Theaters as IconDots, -} from "@mui/icons-material"; -import { JSONSchema7 } from "json-schema"; - -import { MenuGroup } from "./types"; -import { Permission } from "../../../config"; -import { TFunction } from "i18next"; - -const icons = { IconFaceId, IconPaint, IconDots }; - -const topLevel = ["Exhibition", "Person"]; - -const lists: ( - schema: JSONSchema7, - getPermission: (typeName: string) => Permission, - t: TFunction, -) => MenuGroup = (exhibitionSchema, getPermission, t) => ({ - id: "lists", - // title: "Explorieren", - type: "group", - /*children: Object.entries( - exhibitionSchema.definitions || exhibitionSchema["$defs"] || {}, - ) - .map(([key, value]) => ({ - id: `list_${key}`, - title: (value as any).title || key, - type: "item", - url: `/list/${key}`, - typeName: key, - })),*/ - children: [ - { - id: "list_default", - title: "Ausstellungen", - type: "item", - icon: IconPaint as any, - typeName: "Exhibition", - readOnly: !getPermission("Exhibition").edit, - }, - { - id: "list_person", - title: "Personen", - type: "item", - icon: IconFaceId as any, - typeName: "Person", - readOnly: !getPermission("Person").edit, - }, - { - id: "list_other", - title: "Entitäten", - type: "collapse", - //@ts-ignore - icon: icons.IconDots, - children: Object.entries( - exhibitionSchema.definitions || exhibitionSchema["$defs"] || {}, - ) - .filter(([key]) => !topLevel.includes(key)) - .map(([key, value]) => ({ - id: `list_${key}`, - title: t(key), - type: "item", - typeName: key, - readOnly: !getPermission(key).edit, - })), - }, - ], -}); - -export default lists; diff --git a/apps/exhibition-live/components/lists/DeclarativeDatagrid.tsx b/apps/exhibition-live/components/lists/DeclarativeDatagrid.tsx deleted file mode 100644 index 23f7b154..00000000 --- a/apps/exhibition-live/components/lists/DeclarativeDatagrid.tsx +++ /dev/null @@ -1,240 +0,0 @@ -import "@inovua/reactdatagrid-community/index.css"; - -import DataGrid from "@inovua/reactdatagrid-community"; -import BoolEditor from "@inovua/reactdatagrid-community/BoolEditor"; -import BoolFilter from "@inovua/reactdatagrid-community/BoolFilter"; -import DateFilter from "@inovua/reactdatagrid-community/DateFilter"; -import NumberFilter from "@inovua/reactdatagrid-community/NumberFilter"; -import StringFilter from "@inovua/reactdatagrid-community/StringFilter"; -import { - TypeColumn, - TypeComputedProps, - TypeDataGridProps, - TypeFilterValue, - TypeSingleFilterValue, -} from "@inovua/reactdatagrid-community/types"; -import { TypeColumns } from "@inovua/reactdatagrid-community/types/TypeColumn"; -import { TypeOnSelectionChangeArg } from "@inovua/reactdatagrid-community/types/TypeDataGridProps"; -import { CheckBox, CheckBoxOutlineBlank } from "@mui/icons-material"; -import { extendSxProp } from "@mui/system"; -import React, { - ReactNode, - useCallback, - useEffect, - useRef, - useState, -} from "react"; - -import { filterUndefOrNull } from "../utils/core"; -import { ColumnRaw } from "./datagrid/columnRaw"; -import extendedFilter from "./datagrid/extendedFilter"; -import { transformValue } from "./datagrid/tableValueMapper"; - -//global.moment = moment - -export type DeclarativeDataGridProps = { - data?: T[]; - onFilteredDataChange?: (data: T[]) => void; - columnsRaw: ColumnRaw[]; - firstColumns?: TypeColumns; - onRowSelect?: (id: string) => void; - selectedId?: string | null; - debugEnabled: boolean; -} & Partial; - -const filterMappings = { - string: StringFilter, - boolean: BoolFilter, - number: NumberFilter, - date: DateFilter, -}; -const editorMappings = { - boolean: BoolEditor, -}; -const operatorsForType = { - number: "gte", - string: "contains", - date: "beforeOrOn", - boolean: "eq", -}; - -type CustomRendererMatcher = { - match: { [key: string]: any }; - render: (...args: any[]) => ReactNode; -}; - -function Email({ value }: { value: string }) { - const href = `mailto:${value}`; - return {value}; -} - -function Phone({ value }: { value: string }) { - const href = `tel:${value}`; - return {value}; -} - -const customRendererForType: CustomRendererMatcher[] = [ - { - match: { type: "boolean" }, - render: ({ value }) => (!!value ? : ), - }, - { - match: { type: "string", name: "contact_email" }, - render: Email, - }, - { - match: { type: "string", name: "contact_phone" }, - render: Phone, - }, -]; - -const findMatchingRenderer = (c: Partial) => - customRendererForType.find((d) => - Object.keys(d.match).reduce( - (prev, cur) => prev && (c as any)[cur] === d.match[cur], - true, - ), - )?.render; - -const columns = (columnsRaw: ColumnRaw[], firstColumns?: TypeColumns) => [ - ...(firstColumns || []), - ...columnsRaw.map((c) => ({ - ...c, - render: findMatchingRenderer(c) || undefined, - filterEditor: - filterMappings[c.type as "string" | "number" | "boolean" | "date"], - editor: editorMappings[c.type as "boolean"], - })), -]; - -function defaultFilterValue(columnsRaw: ColumnRaw[]) { - return columnsRaw - .filter( - ({ type }) => - type && ["string", "number", "boolean", "date"].includes(type), - ) - .map(({ name, type, options }) => { - return { - name, - type, - value: null, - operator: - options?.filter?.operator || - operatorsForType[type as "string" | "number" | "date" | "boolean"], - } as unknown as TypeSingleFilterValue; - }); -} - -const DeclarativeDataGrid = ({ - data, - onFilteredDataChange, - columnsRaw, - onRowSelect, - selectedId, - firstColumns, - debugEnabled, - ...props -}: DeclarativeDataGridProps) => { - const [dataSource, setDataSource] = useState([]); - const [filteredData, setFilteredData] = useState([]); - const [filterValue, setFilterValue] = useState( - defaultFilterValue(columnsRaw), - ); - - const filterValueChangeHandler = useCallback( - (_filterValue?: TypeFilterValue) => { - setFilterValue(_filterValue); - }, - [setFilterValue], - ); - - const filterAndSetData = useCallback(() => { - if (!filterValue) { - setFilteredData(dataSource); - onFilteredDataChange && onFilteredDataChange(dataSource); - return; - } - const data = extendedFilter(dataSource, filterValue, columnsRaw); - onFilteredDataChange && onFilteredDataChange(data); - setFilteredData(data); - }, [ - columnsRaw, - dataSource, - onFilteredDataChange, - setFilteredData, - filterValue, - ]); - - useEffect(() => { - filterAndSetData(); - }, [columnsRaw, dataSource, filterValue, filterAndSetData]); - - useEffect(() => { - if (!data) return; - const _data = filterUndefOrNull(data).map((v) => - transformValue(v, columnsRaw), - ); - - _data && setDataSource(_data); - }, [columnsRaw, data]); - - const gridRef = useRef(null); - const scrollTo = useCallback( - (id: string) => { - gridRef.current?.scrollToId(id, { duration: 300 }); - }, - [gridRef], - ); - - /* - const debugPrint = useCallback((selectedId) => { - debugEnabled && console.log({selectedData: data.filter(d => (d as any).id === selectedId)}) - }, [data, debugEnabled])*/ - - useEffect(() => { - selectedId && scrollTo(selectedId); - }, [selectedId, scrollTo]); - - const handleRowSelect = useCallback( - ({ selected }: TypeOnSelectionChangeArg) => { - typeof selected === "string" && onRowSelect && onRowSelect(selected); - }, - [onRowSelect], - ); - - const activeIndex2RowSelect = useCallback( - (index: number) => { - try { - // @ts-ignore - const t = gridRef.current?.getRowId(index) as string | undefined; - typeof t === "string" && onRowSelect && onRowSelect(t); - } catch (e) {} - }, - [onRowSelect, gridRef], - ); - - return ( - - (gridRef.current = computedPropsRef.current) - } - showColumnMenuFilterOptions={true} - showFilteringMenuItems={true} - filterValue={filterValue} - onFilterValueChange={filterValueChangeHandler} - rowIndexColumn - enableColumnAutosize={false} - columns={columns(columnsRaw, firstColumns) as TypeColumn[]} - dataSource={filteredData} - style={{ height: "100%" }} - selected={selectedId} - onSelectionChange={handleRowSelect} - onActiveIndexChange={activeIndex2RowSelect} - {...props} - /> - ); -}; - -export default DeclarativeDataGrid; diff --git a/apps/exhibition-live/components/lists/datagrid/columnRaw.ts b/apps/exhibition-live/components/lists/datagrid/columnRaw.ts deleted file mode 100644 index 6e371dbe..00000000 --- a/apps/exhibition-live/components/lists/datagrid/columnRaw.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { - Array2StringTransformOptions, - DateToISOTransformOptions, -} from "./tableValueMapper"; - -export type ColumnOptions = { - dateFormat?: string; - filter?: { - operator?: string; - }; - transform?: { - array2string?: Array2StringTransformOptions; - date2Iso?: DateToISOTransformOptions; - }; -}; -export interface ColumnRaw { - name: string; - header: string; - type: string; - editable?: boolean; - defaultWidth?: number; - group?: string; - options?: ColumnOptions; -} diff --git a/apps/exhibition-live/components/lists/datagrid/extendedFilter.ts b/apps/exhibition-live/components/lists/datagrid/extendedFilter.ts deleted file mode 100644 index 871dabbe..00000000 --- a/apps/exhibition-live/components/lists/datagrid/extendedFilter.ts +++ /dev/null @@ -1,47 +0,0 @@ -import filter from "@inovua/reactdatagrid-community/filter"; -import { - TypeColumn, - TypeSingleFilterValue, -} from "@inovua/reactdatagrid-community/types"; -import dayjs from "dayjs"; - -import { ColumnRaw } from "./columnRaw"; - -const defaultDateFormat = "MM/DD/YYYY"; -const extendedFilter: ( - data: T[], - filterValue: TypeSingleFilterValue[], - columnsRaw: ColumnRaw[], -) => T[] = ( - data: T[], - filterValue: TypeSingleFilterValue[], - columnsRaw: ColumnRaw[], -) => { - const columns = columnsRaw - .filter(({ type }) => type === "date") - .reduce( - (prev, cur) => ({ - ...prev, - [cur.name]: { - dateFormat: cur.options?.dateFormat || defaultDateFormat, - }, - }), - {}, - ); - return filter( - data, - filterValue.map((fV) => { - if (typeof fV.value == "string" && fV.type === "date") { - return { - ...fV, - value: dayjs(fV.value).format(defaultDateFormat), - }; - } - return fV; - }), - undefined, - columns, - ) as T[]; -}; - -export default extendedFilter; diff --git a/apps/exhibition-live/components/lists/datagrid/genateColumnRawDefinition.ts b/apps/exhibition-live/components/lists/datagrid/genateColumnRawDefinition.ts deleted file mode 100644 index a11a1af0..00000000 --- a/apps/exhibition-live/components/lists/datagrid/genateColumnRawDefinition.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * you can generate an inital raw column json by running the following - * function - */ -const makeColumnDefinition = (data: any) => - Object.keys(data).map((k) => ({ - name: k, - header: k.replace(/_/g, " "), - type: - typeof data[k] === "object" && data[k] instanceof Date - ? "date" - : typeof data[k], - })); - -export default makeColumnDefinition; diff --git a/apps/exhibition-live/components/lists/datagrid/tableValueMapper.ts b/apps/exhibition-live/components/lists/datagrid/tableValueMapper.ts deleted file mode 100644 index 8b01ee1f..00000000 --- a/apps/exhibition-live/components/lists/datagrid/tableValueMapper.ts +++ /dev/null @@ -1,54 +0,0 @@ -import dayjs from "dayjs"; - -import { ColumnRaw } from "./columnRaw"; - -export type Array2StringTransformOptions = { - join?: string; -}; - -export type DateToISOTransformOptions = { - inputDateFormat?: string; - outputDateFormat?: string; -}; - -const array2string = (value: string[], options: Array2StringTransformOptions) => - value.join(options.join || " "); - -const callOneOrMany: ( - els: T | T[], - cb: (d: T, ...rest: any[]) => O, - args?: any[], -) => O | O[] = (els, cb, args = []) => - Array.isArray(els) ? els.map((v) => cb(v, ...args)) : cb(els, ...args); - -const dateToIso: ( - date: string, - options: DateToISOTransformOptions, -) => string = (date, { inputDateFormat, outputDateFormat }) => - dayjs(date, inputDateFormat).format(outputDateFormat); - -export const transformValue: (values: T, columnsRaw: ColumnRaw[]) => T = ( - values, - columnsRaw, -) => { - const newValues = { ...values }; - columnsRaw.forEach((c) => { - const transform = c.options?.transform; - if (!transform) return; - // @ts-ignore - let value = values[c.name]; - if (!value) return; - if (transform.date2Iso?.inputDateFormat) { - value = callOneOrMany(value, dateToIso, [transform.date2Iso]); - } - if (transform.array2string && Array.isArray(value)) { - try { - // @ts-ignore - newValues[c.name] = array2string(value, transform.array2string); - } catch (e) { - console.error("cannot transform"); - } - } - }); - return newValues; -}; diff --git a/apps/exhibition-live/components/lists/index.ts b/apps/exhibition-live/components/lists/index.ts deleted file mode 100644 index 99e8fb04..00000000 --- a/apps/exhibition-live/components/lists/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./OverflowContainer"; -export * from "./DeclarativeDatagrid"; diff --git a/apps/exhibition-live/components/mapping/MappingConfigurationDialog.tsx b/apps/exhibition-live/components/mapping/MappingConfigurationDialog.tsx index c1b323cb..90ab274f 100644 --- a/apps/exhibition-live/components/mapping/MappingConfigurationDialog.tsx +++ b/apps/exhibition-live/components/mapping/MappingConfigurationDialog.tsx @@ -8,9 +8,9 @@ import { IconButton, Typography, } from "@mui/material"; -import { useCallback, useState } from "react"; +import { useCallback } from "react"; -import { DeclarativeSimpleMapping } from "../utils/mapping/mappingStrategies"; +import type { DeclarativeSimpleMapping } from "@slub/edb-data-mapping"; import { MappingConfiguration } from "./MappingConfiguration"; type MappingConfigurationDialogProps = { diff --git a/apps/exhibition-live/components/provider/adbContext.tsx b/apps/exhibition-live/components/provider/adbContext.tsx deleted file mode 100644 index 3ddbfb78..00000000 --- a/apps/exhibition-live/components/provider/adbContext.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { createContext } from "react"; -import { useOptionalLiveDemoEndpoint } from "../state/useOptionalLiveDemoEndpoint"; - -type AdbContextValue = {}; -export const AdbContext = createContext({}); - -export const AdbProvider = ({ children }: { children: React.ReactNode }) => { - useOptionalLiveDemoEndpoint(); - return {children}; -}; diff --git a/apps/exhibition-live/components/provider/formRefsContext.tsx b/apps/exhibition-live/components/provider/formRefsContext.tsx deleted file mode 100644 index 99eacba4..00000000 --- a/apps/exhibition-live/components/provider/formRefsContext.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import React, { - createContext, - createRef, - ForwardedRef, - RefObject, -} from "react"; - -type FormRefsContextValue = { - stepperRef: RefObject; - actionRef: RefObject; - toolbarRef?: RefObject; - searchRef?: RefObject; -}; -export const FormRefsContext = createContext({ - stepperRef: undefined, - actionRef: undefined, - toolbarRef: undefined, - searchRef: undefined, -}); - -export const useFormRefsContext = () => React.useContext(FormRefsContext); - -const stepperRef = createRef(); -const actionRef = createRef(); -const toolbarRef = createRef(); -const searchRef = createRef(); -export const FormRefsProvider = ({ - children, -}: { - children: React.ReactNode; -}) => { - return ( - - {children} - - ); -}; diff --git a/apps/exhibition-live/components/provider/index.ts b/apps/exhibition-live/components/provider/index.ts deleted file mode 100644 index 838d0111..00000000 --- a/apps/exhibition-live/components/provider/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./rootFormContext"; -export * from "./formRefsContext"; -export * from "./adbContext"; diff --git a/apps/exhibition-live/components/provider/rootFormContext.tsx b/apps/exhibition-live/components/provider/rootFormContext.tsx deleted file mode 100644 index ba62d218..00000000 --- a/apps/exhibition-live/components/provider/rootFormContext.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { ReactNode, createContext, useContext } from "react"; - -type RootFormContextValue = { - isWithinRootForm: boolean; -}; - -export const RootFormContext = createContext({ - isWithinRootForm: false, -}); - -export const RootFormProvider = ({ children }: { children: ReactNode }) => { - return ( - - {children} - - ); -}; -export const useRootFormContext = () => useContext(RootFormContext); diff --git a/apps/exhibition-live/components/renderer/AdbSpecialDateRenderer.tsx b/apps/exhibition-live/components/renderer/AdbSpecialDateRenderer.tsx deleted file mode 100644 index e923cc7a..00000000 --- a/apps/exhibition-live/components/renderer/AdbSpecialDateRenderer.tsx +++ /dev/null @@ -1,153 +0,0 @@ -import { - and, - ControlProps, - isDescriptionHidden, - isIntegerControl, - or, - RankedTester, - rankWith, - scopeEndsWith, -} from "@jsonforms/core"; -import { useFocus } from "@jsonforms/material-renderers"; -import { withJsonFormsControlProps } from "@jsonforms/react"; -import { - FormControl, - FormGroup, - FormHelperText, - FormLabel, - Hidden, - TextField, -} from "@mui/material"; -import { getDatePart, getPaddedDatePart, leftpad } from "@slub/edb-core-utils"; -import React, { useCallback } from "react"; - -const getDatePartAsString = (date: number, part: "day" | "month" | "year") => { - const value = getDatePart(date, part); - if (value === 0) return ""; - const maxLength = part === "year" ? 4 : 2; - return leftpad(value, maxLength); -}; - -export const AdbSpecialDateControl = (props: ControlProps) => { - const [focused, onFocus, onBlur] = useFocus(); - const { - description, - id, - errors, - label, - uischema, - visible, - enabled, - required, - path, - handleChange, - data, - config, - } = props; - const isValid = errors.length === 0; - //const appliedUiSchemaOptions = merge({}, config, uischema.options) - const showDescription = !isDescriptionHidden( - visible, - description, - focused, - true, - ); - - const firstFormHelperText = showDescription - ? description - : !isValid - ? errors - : null; - const secondFormHelperText = showDescription && !isValid ? errors : null; - - const handleTextFieldChange = useCallback( - ( - event: React.ChangeEvent, - field: "day" | "month" | "year", - ) => { - const maxLength = field === "year" ? 4 : 2, - maxValue = field === "year" ? 9999 : field === "month" ? 12 : 31, - newValueNumber = Number(event.target.value); - if (isNaN(newValueNumber) || newValueNumber > maxValue) return; - const newValue = String(newValueNumber); - if (newValue.length > maxLength) return; - let strData, paddedValue; - try { - paddedValue = leftpad(newValueNumber, maxLength); - } catch (e) { - return; - } - - // check if the day is valid, if not, set it to the last day of the month (and handle leap years) - let changeDay = - field === "day" ? paddedValue : getPaddedDatePart(data, "day"); - const currentMonth = getDatePart(data, "month"), - currentYear = getDatePart(data, "year"); - if (currentMonth > 0) { - const lastDayOfMonth = new Date( - currentYear ?? 4, - currentMonth, - 0, - ).getDate(); - if (Number(changeDay) > lastDayOfMonth) { - changeDay = leftpad(lastDayOfMonth, 2); - } - } - if (field === "day") - strData = - getPaddedDatePart(data, "year") + - getPaddedDatePart(data, "month") + - changeDay; - else if (field === "month") - strData = getPaddedDatePart(data, "year") + paddedValue + changeDay; - else strData = paddedValue + getPaddedDatePart(data, "month") + changeDay; - handleChange(path, Number(strData)); - }, - [path, handleChange, data], - ); - - return ( - - - {label && label.length > 0 && {label}} - - handleTextFieldChange(e, "day")} - /> - handleTextFieldChange(e, "month")} - label={"Monat"} - value={getDatePartAsString(data ?? 0, "month")} - /> - handleTextFieldChange(e, "year")} - label={"Jahr"} - value={getDatePartAsString(data ?? 0, "year")} - /> - - - {firstFormHelperText} - - {secondFormHelperText} - - - ); -}; - -export const adbSpecialDateControlTester: RankedTester = rankWith( - 6, - and(isIntegerControl, or(scopeEndsWith("dateValue"), scopeEndsWith("Date"))), -); - -export default withJsonFormsControlProps(AdbSpecialDateControl); diff --git a/apps/exhibition-live/components/renderer/ArrayToolbar.tsx b/apps/exhibition-live/components/renderer/ArrayToolbar.tsx deleted file mode 100644 index 2466b196..00000000 --- a/apps/exhibition-live/components/renderer/ArrayToolbar.tsx +++ /dev/null @@ -1,241 +0,0 @@ -import { - Box, - Grid, - IconButton, - TextField, - Tooltip, - Typography, -} from "@mui/material"; -import * as React from "react"; -import { useTranslation } from "next-i18next"; -import { v4 as uuidv4 } from "uuid"; - -import DiscoverAutocompleteInput from "../form/discover/DiscoverAutocompleteInput"; -import { useCallback, useMemo } from "react"; -import { JsonSchema7 } from "@jsonforms/core"; -import { slent } from "../form/formConfigs"; -import { BASE_IRI, primaryFields, typeIRItoTypeName } from "../config"; -import { memo } from "./config"; -import { - useGlobalSearchWithHelper, - useKeyEventForSimilarityFinder, - useRightDrawerState, - useSimilarityFinderState, -} from "../state"; -import { SearchbarWithFloatingButton } from "../layout/main-layout/Searchbar"; -import SimilarityFinder from "../form/SimilarityFinder"; -import { JSONSchema7 } from "json-schema"; -import { AutocompleteSuggestion } from "../form/DebouncedAutoComplete"; -import { NoteAdd } from "@mui/icons-material"; -import { PrimaryField } from "../utils/types"; - -export interface ArrayLayoutToolbarProps { - label: string; - errors: string; - path: string; - - addItem(path: string, data: any): () => void; - - createDefault(): any; - - readonly?: boolean; - typeIRI?: string; - onCreate?: () => void; - isReifiedStatement?: boolean; -} - -const getDefaultLabelKey = (typeIRI?: string) => { - const typeName = typeIRItoTypeName(typeIRI); - const fieldDefinitions = primaryFields[typeName] as PrimaryField | undefined; - return fieldDefinitions?.label || "title"; -}; -export const ArrayLayoutToolbar = memo( - ({ - label, - errors, - addItem, - path, - schema, - readonly, - onCreate, - isReifiedStatement, - formsPath, - }: ArrayLayoutToolbarProps & { - schema?: JsonSchema7; - formsPath?: string; - }) => { - const { t } = useTranslation(); - const typeIRI = useMemo( - () => schema?.properties?.["@type"]?.const, - [schema], - ); - const handleSelectedChange = React.useCallback( - (v: AutocompleteSuggestion) => { - if (!v) return; - addItem(path, { - "@id": v.value, - __label: v.label, - })(); - }, - [addItem, path], - ); - const handleCreateNewFromSearch = React.useCallback( - (value?: string) => { - if (!value) return; - addItem(path, { - "@id": slent(uuidv4()).value, - "@type": typeIRI, - __draft: true, - [getDefaultLabelKey(typeIRI)]: value, - })(); - }, - [addItem, path, typeIRI], - ); - const typeName = useMemo( - () => typeIRI?.substring(BASE_IRI.length, typeIRI.length), - [typeIRI], - ); - const handleEntityIRIChange = useCallback( - (iri: string) => { - handleSelectedChange({ value: iri, label: iri }); - }, - [handleSelectedChange], - ); - - const handleExistingEntityAccepted = useCallback( - (iri: string, data: any) => { - console.log("onExistingEntityAccepted", { iri, data }); - const label = data[getDefaultLabelKey(typeIRI)] || data.label || iri; - //handleSelectedChange({ value: iri, label }); - addItem(path, data)(); - inputRef.current?.focus(); - }, - [addItem, typeIRI], - ); - - const handleMappedDataAccepted = useCallback( - (newData: any) => { - addItem(path, newData)(); - inputRef.current?.focus(); - }, - [addItem, path], - ); - - const { open: sidebarOpen } = useRightDrawerState(); - - const inputRef = React.useRef(null); - const { - path: globalPath, - searchString, - handleSearchStringChange, - handleMappedData, - handleFocus, - isActive, - } = useGlobalSearchWithHelper( - typeName, - typeIRI, - schema as JSONSchema7, - formsPath, - handleMappedDataAccepted, - ); - - const handleKeyUp = useKeyEventForSimilarityFinder(); - const { keepMounted } = useRightDrawerState(); - - return ( - - {isReifiedStatement && ( - - {label} - - )} - - {(keepMounted || sidebarOpen) && !isReifiedStatement ? ( - handleSearchStringChange(ev.target.value)} - value={searchString || ""} - sx={(theme) => ({ - marginTop: theme.spacing(1), - marginBottom: theme.spacing(1), - })} - inputProps={{ - ref: inputRef, - onFocus: handleFocus, - onKeyUp: handleKeyUp, - }} - /> - ) : ( - - {!isReifiedStatement && ( - - - - - - - - - - - - - - - )} - - )} - {globalPath === formsPath && ( - - - - )} - - - ); - }, -); diff --git a/apps/exhibition-live/components/renderer/AutocompleteGNDFieldRenderer.tsx b/apps/exhibition-live/components/renderer/AutocompleteGNDFieldRenderer.tsx deleted file mode 100644 index a5b74e75..00000000 --- a/apps/exhibition-live/components/renderer/AutocompleteGNDFieldRenderer.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import { ControlProps, showAsRequired, update } from "@jsonforms/core"; -import { withJsonFormsControlProps } from "@jsonforms/react"; -import { Edit, EditOff } from "@mui/icons-material"; -import { - FormControl, - FormLabel, - Grid, - Hidden, - IconButton, -} from "@mui/material"; -import merge from "lodash/merge"; -import React, { useCallback, useEffect, useMemo, useState } from "react"; - -import { AutocompleteSuggestion } from "../form/DebouncedAutoComplete"; -import GNDAutocompleteInput from "../form/gnd/GNDAutocompleteInput"; - -const AutocompleteGNDFieldRenderer = (props: ControlProps) => { - const { - id, - errors, - label, - schema, - uischema, - visible, - required, - config, - data, - handleChange, - path, - } = props; - const isValid = errors.length === 0; - const appliedUiSchemaOptions = merge({}, config, uischema.options); - const [editMode, setEditMode] = useState(false); - const [selected, setSelected] = useState(null); - - const classType = useMemo( - () => schema.format?.substring("gndo-".length), - [schema], - ); - - const handleChange_ = useCallback( - (v?: string) => { - handleChange(path, v); - }, - [path, handleChange], - ); - - useEffect(() => { - handleChange_(selected ? selected.value : undefined); - }, [selected, handleChange_]); - - return ( - - ({ marginBottom: theme.spacing(2) })} - hiddenLabel={true} - > - - - - GND - - {" "} - {data} - - - - - ); -}; - -export default withJsonFormsControlProps(AutocompleteGNDFieldRenderer); diff --git a/apps/exhibition-live/components/renderer/AutocompleteURIFieldRenderer.stories.tsx b/apps/exhibition-live/components/renderer/AutocompleteURIFieldRenderer.stories.tsx index a7d4d2a9..51758a03 100644 --- a/apps/exhibition-live/components/renderer/AutocompleteURIFieldRenderer.stories.tsx +++ b/apps/exhibition-live/components/renderer/AutocompleteURIFieldRenderer.stories.tsx @@ -16,7 +16,7 @@ import { useCallback, useState } from "react"; import AutocompleteURIFieldRenderer from "./AutocompleteURIFieldRenderer"; export default { - title: "form/exhibition/AutocompleteURIFieldRenderer", + title: "ui/form/renderer/AutocompleteURIFieldRenderer", component: AutocompleteURIFieldRenderer, }; diff --git a/apps/exhibition-live/components/renderer/AutocompleteURIFieldRenderer.tsx b/apps/exhibition-live/components/renderer/AutocompleteURIFieldRenderer.tsx index 684696a0..2645482c 100644 --- a/apps/exhibition-live/components/renderer/AutocompleteURIFieldRenderer.tsx +++ b/apps/exhibition-live/components/renderer/AutocompleteURIFieldRenderer.tsx @@ -1,17 +1,10 @@ import { ControlProps, showAsRequired, update } from "@jsonforms/core"; import { withJsonFormsControlProps } from "@jsonforms/react"; -import { Edit, EditOff } from "@mui/icons-material"; -import { - FormControl, - FormLabel, - Grid, - Hidden, - IconButton, -} from "@mui/material"; +import { FormControl, FormLabel, Grid, Hidden } from "@mui/material"; import merge from "lodash/merge"; import React, { useCallback, useEffect, useMemo, useState } from "react"; -import { AutocompleteSuggestion } from "../form/DebouncedAutoComplete"; +import { AutocompleteSuggestion } from "@slub/edb-core-types"; import WikidataAutocompleteInput from "../form/wikidata/WikidataAutocompleteInput"; const AutocompleteURIFieldRenderer = (props: ControlProps) => { diff --git a/apps/exhibition-live/components/renderer/DeleteDialog.tsx b/apps/exhibition-live/components/renderer/DeleteDialog.tsx deleted file mode 100644 index 5635fcba..00000000 --- a/apps/exhibition-live/components/renderer/DeleteDialog.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { - Button, - Dialog, - DialogActions, - DialogContent, - DialogContentText, - DialogTitle, -} from "@mui/material"; -import React from "react"; -import { memo } from "./config"; - -export interface DeleteDialogProps { - open: boolean; - onClose(): void; - onConfirm(): void; - onCancel(): void; -} - -export interface WithDeleteDialogSupport { - openDeleteDialog(path: string, data: number): void; -} - -export const DeleteDialog = memo( - ({ open, onClose, onConfirm, onCancel }: DeleteDialogProps) => { - return ( - - - {"Confirm Deletion"} - - - - Are you sure you want to delete the selected entry? - - - - - - - - ); - }, -); diff --git a/apps/exhibition-live/components/renderer/EnumRenderer.tsx b/apps/exhibition-live/components/renderer/EnumRenderer.tsx deleted file mode 100644 index 0a56f907..00000000 --- a/apps/exhibition-live/components/renderer/EnumRenderer.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { JsonSchema } from "@jsonforms/core"; -import { withJsonFormsControlProps } from "@jsonforms/react"; -import FormControl from "@mui/material/FormControl"; -import FormControlLabel from "@mui/material/FormControlLabel"; -import FormLabel from "@mui/material/FormLabel"; -import Hidden from "@mui/material/Hidden"; -import Radio from "@mui/material/Radio"; -import RadioGroup from "@mui/material/RadioGroup"; -import React from "react"; -import { useTranslation } from "next-i18next"; -import { memo } from "./config"; - -type EnumRendererProps = { - data: any; - handleChange(path: string, value: any): void; - path: string; - label: string; - schema: JsonSchema; - visible?: boolean; -}; - -const EnumRenderer = memo( - ({ data, handleChange, path, label, schema, visible }: EnumRendererProps) => { - const { t } = useTranslation(); - - return ( - - - {t(label)} - handleChange(path, ev.target.value)} - aria-labelledby={`enum-label-${path}`} - sx={{ flexDirection: "row" }} - > - {(schema.enum || []).map((value) => ( - } - label={`${t(value)}`} - /> - ))} - - - - ); - }, -); - -export default withJsonFormsControlProps(EnumRenderer); diff --git a/apps/exhibition-live/components/renderer/InlineSemanticFormsModal.tsx b/apps/exhibition-live/components/renderer/InlineSemanticFormsModal.tsx deleted file mode 100644 index 9bf924f1..00000000 --- a/apps/exhibition-live/components/renderer/InlineSemanticFormsModal.tsx +++ /dev/null @@ -1,166 +0,0 @@ -import { JsonSchema, resolveSchema, UISchemaElement } from "@jsonforms/core"; -import { JSONSchema7 } from "json-schema"; -import React, { useCallback, useMemo, useState } from "react"; - -import DiscoverAutocompleteInput from "../form/discover/DiscoverAutocompleteInput"; -import { SemanticJsonFormsProps } from "../form/SemanticJsonForm"; -import { useUISchemaForType } from "../form/uischemaForType"; -import { uischemas } from "../form/uischemas"; -import MuiEditDialog from "./MuiEditDialog"; -import { BASE_IRI } from "../config"; -import { SemanticJsonFormNoOps } from "../form/SemanticJsonFormNoOps"; -import { useCRUDWithQueryClient } from "../state/useCRUDWithQueryClient"; -import NiceModal from "@ebay/nice-modal-react"; -import GenericModal from "../form/GenericModal"; -import { useSnackbar } from "notistack"; -import { irisToData } from "../utils/core"; - -type InlineSemanticFormsModalProps = { - label?: string; - path: string; - open: boolean; - askClose: () => void; - semanticJsonFormsProps?: Partial; - schema: JsonSchema; - rootSchema: JsonSchema; - uischema: UISchemaElement; - data: any; - handleChange: (path: string, value: any) => void; -}; -export const InlineSemanticFormsModal = ( - props: InlineSemanticFormsModalProps, -) => { - const { - open, - schema, - uischema, - data, - handleChange, - path, - rootSchema, - label, - askClose, - semanticJsonFormsProps, - } = props; - const { $ref, typeIRI } = uischema.options?.context || {}; - const [formData, setFormData] = useState(irisToData(data, typeIRI)); - const [editMode, setEditMode] = useState(true); - const [searchText, setSearchText] = useState(); - - const handleChange_ = useCallback( - (v?: string) => { - //FIXME: this is a workaround for a bug, that causes this to be called with the same value eternally - if (v === data) return; - handleChange(path, v); - }, - [path, handleChange, data], - ); - - const uischemaExternal = useUISchemaForType(typeIRI); - const typeName = useMemo( - () => typeIRI && typeIRI.substring(BASE_IRI.length, typeIRI.length), - [typeIRI], - ); - - const subSchema: JSONSchema7 = useMemo(() => { - const schema2 = { - ...schema, - $ref, - }; - const resolvedSchema = resolveSchema( - schema2 as JsonSchema, - "", - rootSchema as JsonSchema, - ); - return { - ...rootSchema, - ...resolvedSchema, - } as JSONSchema7; - }, [$ref, schema, rootSchema]); - - const handleSearchTextChange = useCallback( - (searchText: string | undefined) => { - setSearchText(searchText); - }, - [setSearchText], - ); - - const { loadQuery, existsQuery, saveMutation, removeMutation } = - useCRUDWithQueryClient(data, typeIRI, subSchema, { enabled: false }); - - const { enqueueSnackbar } = useSnackbar(); - const handleSave = useCallback(async () => { - saveMutation - .mutateAsync(data) - .then(async (skipLoading?: boolean) => { - enqueueSnackbar("Saved", { variant: "success" }); - !skipLoading && (await loadQuery.refetch()); - }) - .catch((e) => { - enqueueSnackbar("Error while saving " + e.message, { - variant: "error", - }); - }); - }, [enqueueSnackbar, saveMutation, loadQuery, data]); - - const handleRemove = useCallback(async () => { - NiceModal.show(GenericModal, { - type: "delete", - }).then(() => { - removeMutation.mutate(); - }); - }, [removeMutation]); - - const handleReload = useCallback(async () => { - NiceModal.show(GenericModal, { - type: "reload", - }).then(() => { - loadQuery.refetch(); - }); - }, [loadQuery]); - - const handleEditToggle = useCallback(() => { - setEditMode(!editMode); - }, [editMode, setEditMode]); - return ( - handleChange_(selection?.value)} - /> - } - onRemove={handleRemove} - > - <> - {subSchema && ( - - )} - - - ); -}; diff --git a/apps/exhibition-live/components/renderer/InlineTextFieldRenderer.tsx b/apps/exhibition-live/components/renderer/InlineTextFieldRenderer.tsx deleted file mode 100644 index 806d06ce..00000000 --- a/apps/exhibition-live/components/renderer/InlineTextFieldRenderer.tsx +++ /dev/null @@ -1,343 +0,0 @@ -import { - ControlProps, - JsonSchema, - Resolve, - resolveSchema, -} from "@jsonforms/core"; -import { useJsonForms, withJsonFormsControlProps } from "@jsonforms/react"; -import { - FormControl, - Grid, - Hidden, - IconButton, - TextField, -} from "@mui/material"; -import merge from "lodash/merge"; -import React, { useCallback, useEffect, useMemo, useState } from "react"; -import { v4 as uuidv4 } from "uuid"; - -import { slent } from "../form/formConfigs"; -import { Add, OpenInNew, OpenInNewOff } from "@mui/icons-material"; -import { primaryFields, typeIRItoTypeName } from "../config"; -import { AutocompleteSuggestion } from "../form/DebouncedAutoComplete"; -import { SemanticFormsModal } from "./SemanticFormsModal"; -import { extractFieldIfString } from "../utils/mapping/simpleFieldExtractor"; -import { PrimaryField } from "../utils/types"; -import { useGlobalSearchWithHelper } from "../state"; -import { encodeIRI, makeFormsPath } from "../utils/core"; -import { SearchbarWithFloatingButton } from "../layout/main-layout/Searchbar"; -import SimilarityFinder from "../form/SimilarityFinder"; -import { JSONSchema7 } from "json-schema"; -import { useRouter } from "next/router"; -import { useTranslation } from "next-i18next"; - -const InlineTextFieldRenderer = (props: ControlProps) => { - const { - id, - errors, - schema, - uischema, - visible, - required, - renderers, - config, - data, - handleChange, - path, - rootSchema, - label, - description, - } = props; - const enableDrawer = true; - const [formData, setFormData] = useState({ "@id": data }); - const isValid = errors.length === 0; - const appliedUiSchemaOptions = merge({}, config, uischema.options); - const [editMode, setEditMode] = useState(false); - const ctx = useJsonForms(); - const [realLabel, setRealLabel] = useState(""); - const [modalIsOpen, setModalIsOpen] = useState(false); - const formsPath = useMemo( - () => makeFormsPath(config?.formsPath, path), - [config?.formsPath, path], - ); - const selected = useMemo( - () => - data - ? { value: data || null, label: realLabel } - : { value: null, label: null }, - [data, realLabel], - ); - const { $ref, typeIRI } = appliedUiSchemaOptions.context || {}; - const subSchema = useMemo(() => { - if (!$ref) return; - const schema2 = { - ...schema, - $ref, - }; - const resolvedSchema = resolveSchema( - schema2 as JsonSchema, - "", - rootSchema as JsonSchema, - ); - return { - ...rootSchema, - ...resolvedSchema, - }; - }, [$ref, schema, rootSchema]); - - useEffect(() => { - if (!data) setRealLabel(""); - }, [data, setRealLabel]); - - const handleSelectedChange = useCallback( - (v: AutocompleteSuggestion) => { - if (!v) { - handleChange(path, undefined); - return; - } - if (v.value !== data) handleChange(path, v.value); - setFormData({ "@id": v.value }); - setRealLabel(v.label); - }, - [path, handleChange, data, setRealLabel, setFormData], - ); - - useEffect(() => { - setRealLabel((_old) => { - if ((_old && _old.length > 0) || !data) return _old; - const parentData = Resolve.data( - ctx?.core?.data, - path.substring(0, path.length - ("@id".length + 1)), - ); - const fieldDecl = primaryFields[typeName] as PrimaryField | undefined; - let label = ""; - if (fieldDecl?.label) - label = extractFieldIfString(parentData, fieldDecl.label); - if (typeof label === "object") { - return ""; - } - return label; - }); - }, [data, ctx?.core?.data, path, setRealLabel]); - - const handleExistingEntityAccepted = useCallback( - (entityIRI: string, data: any) => { - handleSelectedChange({ - value: entityIRI, - label: data.label || entityIRI, - }); - }, - [handleSelectedChange], - ); - - const typeName = useMemo( - () => typeIRI && typeIRItoTypeName(typeIRI), - [typeIRI], - ); - - const router = useRouter(); - const locale = router.query.locale || ""; - const handleToggle = useCallback( - (event?: React.MouseEvent) => { - event?.stopPropagation(); - //open new tab if middle mouse click - if (event?.button === 1) { - window.open( - `/${locale}/create/${typeName}?encID=${encodeIRI(data)}`, - "_blank", - ); - return; - } - setModalIsOpen(!modalIsOpen); - }, - [setModalIsOpen, modalIsOpen, locale, typeName], - ); - - const searchOnDataPath = useMemo(() => { - const typeName = typeIRItoTypeName(typeIRI); - return primaryFields[typeName]?.label; - }, [typeIRI]); - - const handleSaveAndClose = useCallback(() => { - setModalIsOpen(false); - const id = formData["@id"]; - if (!id) return; - const fieldDecl = primaryFields[typeName] as PrimaryField | undefined; - let label = id; - if (fieldDecl?.label) - label = extractFieldIfString(formData, fieldDecl.label); - handleSelectedChange({ - value: id, - label: typeof label === "string" ? label : id, - }); - }, [setModalIsOpen, formData, handleSelectedChange]); - - const handleClose = useCallback(() => { - setModalIsOpen(false); - }, [setModalIsOpen]); - - const handleFormDataChange = useCallback( - (data: any) => { - setFormData(data); - }, - [setFormData], - ); - - const handleMappedDataAccepted = useCallback( - (newData: any) => { - const newIRI = newData["@id"]; - if (!newIRI) return; - handleSelectedChange({ - value: newIRI, - label: newData.__label || newIRI, - }); - }, - [handleSelectedChange], - ); - const { - path: globalPath, - searchString, - handleSearchStringChange, - handleMappedData, - handleFocus, - isActive, - } = useGlobalSearchWithHelper( - typeName, - typeIRI, - subSchema as JSONSchema7, - formsPath, - handleMappedDataAccepted, - ); - - const newURI = useCallback(() => { - const prefix = slent[""].value; - const iri = `${prefix}${uuidv4()}`; - const fieldDecl = primaryFields[typeName] as PrimaryField | undefined; - const labelKey = fieldDecl?.label || "title"; - setFormData({ "@id": iri, [labelKey]: searchString }); - return iri; - }, [schema, data, searchString, setFormData]); - - const handleAddNew = useCallback( - (event?: React.MouseEvent) => { - event?.stopPropagation(); - newURI(); - setModalIsOpen(true); - }, - [setModalIsOpen, newURI], - ); - - const { t } = useTranslation(); - - const handleAddNewWithinNewTab = useCallback( - (event: React.MouseEvent) => { - if (event.button !== 1) return; - event?.stopPropagation(); - const newIRI = newURI(); - handleSelectedChange({ - value: newIRI, - label: `${t(typeName)} neu (${newIRI.substring( - newIRI.lastIndexOf("/") + 1, - newIRI.length, - )})`, - }); - window.open( - `/${locale}/create/${typeName}?encID=${encodeIRI(newIRI)}`, - "_blank", - ); - }, - [setModalIsOpen, newURI, typeName, locale], - ); - - return ( - - - - handleSearchStringChange(ev.target.value)} - value={searchString || ""} - inputProps={{ - onFocus: handleFocus, - }} - /> - - {!ctx.readonly && ( - - - {typeof data == "string" && data.length > 0 && ( - - - {modalIsOpen ? : } - - - )} - - - {} - - - - { - - } - {globalPath === formsPath && ( - - - - )} - - )} - - - ({ marginBottom: theme.spacing(2) })} - className={"inline_object_card"} - > - - ); -}; - -export default withJsonFormsControlProps(InlineTextFieldRenderer); diff --git a/apps/exhibition-live/components/renderer/ListWithDetailMasterItem.tsx b/apps/exhibition-live/components/renderer/ListWithDetailMasterItem.tsx deleted file mode 100644 index 65b097b8..00000000 --- a/apps/exhibition-live/components/renderer/ListWithDetailMasterItem.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import { ControlElement, JsonSchema } from "@jsonforms/core"; -import { withJsonFormsContext } from "@jsonforms/react"; -import DeleteIcon from "@mui/icons-material/Delete"; -import { - Avatar, - IconButton, - ListItem, - ListItemAvatar, - ListItemSecondaryAction, - ListItemText, -} from "@mui/material"; -import React from "react"; - -import { withContextToMasterListItemProps } from "./withContextToMasterListItem"; - -export interface OwnPropsOfMasterListItem { - index: number; - selected: boolean; - path: string; - schema: JsonSchema; - uischema: ControlElement; - handleSelect(index: number): () => void; - removeItem(path: string, value: number): () => void; -} -export interface StatePropsOfMasterItem extends OwnPropsOfMasterListItem { - childLabel: string; -} - -const ListWithDetailMasterItem = ({ - index, - childLabel, - selected, - handleSelect, - removeItem, - path, -}: StatePropsOfMasterItem) => { - return ( - - - {index + 1} - - - - - - - - - ); -}; - -export default withJsonFormsContext( - withContextToMasterListItemProps(ListWithDetailMasterItem), -); diff --git a/apps/exhibition-live/components/renderer/MaterialArrayLayout.tsx b/apps/exhibition-live/components/renderer/MaterialArrayLayout.tsx deleted file mode 100644 index fbe4677c..00000000 --- a/apps/exhibition-live/components/renderer/MaterialArrayLayout.tsx +++ /dev/null @@ -1,306 +0,0 @@ -/* - The MIT License - - Copyright (c) 2017-2019 EclipseSource Munich - https://github.com/eclipsesource/jsonforms - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*/ -import { - ArrayLayoutProps, - composePaths, - computeLabel, - createDefaultValue, - JsonSchema, - JsonSchema7, - Resolve, -} from "@jsonforms/core"; -import merge from "lodash/merge"; -import React, { - useCallback, - useEffect, - useMemo, - useRef, - useState, -} from "react"; - -import { ArrayLayoutToolbar } from "./ArrayToolbar"; -import { useJsonForms } from "@jsonforms/react"; -import { memo } from "./config"; -import { uniqBy, orderBy, isArray, isEqual } from "lodash"; -import { SimpleExpandPanelRenderer } from "./SimpleExpandPanelRenderer"; -import { SemanticFormsModal } from "./SemanticFormsModal"; -import { BASE_IRI } from "../config"; -import { irisToData, makeFormsPath } from "../utils/core"; -import { JSONSchema7 } from "json-schema"; -import { - defaultJsonldContext, - defaultPrefix, - slent, -} from "../form/formConfigs"; -import { v4 as uuidv4 } from "uuid"; -import { Grid, IconButton, List } from "@mui/material"; -import { SemanticFormsInline } from "./SemanticFormsInline"; -import AddIcon from "@mui/icons-material/Add"; -import { useGlobalCRUDOptions } from "../state/useGlobalCRUDOptions"; -import { useCRUDWithQueryClient } from "../state/useCRUDWithQueryClient"; -import { useSnackbar } from "notistack"; -import { ErrorObject } from "ajv"; -import { bringDefinitionToTop } from "@slub/json-schema-utils"; -import { Pulse } from "../form/utils"; - -type OwnProps = { - removeItems(path: string, toDelete: number[]): () => void; -}; -const MaterialArrayLayoutComponent = (props: ArrayLayoutProps & {}) => { - const [expanded, setExpanded] = useState(false); - const innerCreateDefaultValue = useCallback( - () => createDefaultValue(props.schema), - [props.schema], - ); - const { - data, - path, - schema, - errors, - addItem, - renderers, - cells, - label, - required, - rootSchema, - config, - removeItems, - } = props; - const appliedUiSchemaOptions = merge({}, config, props.uischema.options); - const { readonly, core } = useJsonForms(); - const realData = Resolve.data(core.data, path); - const typeIRI = schema.properties?.["@type"]?.const; - const [modalIsOpen, setModalIsOpen] = useState(false); - const [formData, setFormData] = useState( - irisToData(slent(uuidv4()).value, typeIRI), - ); - - const addButtonRef = useRef(null); - - const handleInlineFormDataChange = useCallback( - (data: any) => { - setFormData(data); - }, - [setFormData], - ); - - const handleCreateNew = useCallback(() => { - setFormData(irisToData(slent(uuidv4()).value, typeIRI)); - setModalIsOpen(true); - }, [setModalIsOpen, setFormData, typeIRI]); - const typeName = useMemo( - () => typeIRI && typeIRI.substring(BASE_IRI.length, typeIRI.length), - [typeIRI], - ); - const subSchema = useMemo( - () => - bringDefinitionToTop(rootSchema as JSONSchema7, typeName) as JsonSchema, - [rootSchema, typeName], - ); - const { crudOptions } = useGlobalCRUDOptions(); - const entityIRI = useMemo(() => formData["@id"], [formData]); - const { saveMutation } = useCRUDWithQueryClient( - entityIRI, - typeIRI, - subSchema as JSONSchema7, - { enabled: false }, - ); - - const { enqueueSnackbar } = useSnackbar(); - const handleSaveAndAdd = useCallback(() => { - const finalData = { - ...formData, - }; - //if(typeof saveMethod === 'function') saveMethod(); - saveMutation - .mutateAsync(finalData) - .then((res) => { - enqueueSnackbar("Saved", { variant: "success" }); - addItem(path, res)(); - const id = slent(uuidv4()).value; - setFormData({ - "@id": id, - "@type": typeIRI, - }); - }) - .catch((e) => { - enqueueSnackbar("Error while saving " + e.message, { - variant: "error", - }); - }); - }, [saveMutation, typeIRI, addItem, setFormData]); - - const handleAddNew = useCallback(() => { - setModalIsOpen(false); - //if(typeof saveMethod === 'function') saveMethod(); - addItem(path, formData)(); - setFormData({}); - }, [setModalIsOpen, addItem, formData, setFormData, typeIRI]); - - const isReifiedStatement = Boolean(appliedUiSchemaOptions.isReifiedStatement); - const autoFocusOnValid = Boolean(appliedUiSchemaOptions.autoFocusOnValid); - const [inlineErrors, setInlineErrors] = useState(null); - const handleErrors = useCallback( - (err: ErrorObject[]) => { - setInlineErrors(err); - }, - [setInlineErrors], - ); - - useEffect(() => { - if ( - inlineErrors?.length === 0 && - addButtonRef.current && - autoFocusOnValid - ) { - addButtonRef.current.focus(); - } - }, [inlineErrors, autoFocusOnValid]); - - const formsPath = useMemo( - () => makeFormsPath(config?.formsPath, path), - [config?.formsPath, path], - ); - - useEffect(() => { - setFormData(irisToData(slent(uuidv4()).value, typeIRI)); - }, [formsPath, typeIRI, setFormData]); - - return ( -
- - {modalIsOpen && ( - setModalIsOpen(false)} - onChange={(entityIRI) => - entityIRI && setFormData({ "@id": entityIRI }) - } - onFormDataChange={(data) => setFormData(data)} - formsPath={makeFormsPath(config?.formsPath, path)} - /> - )} - {isReifiedStatement && ( - - - - - - 0} - onClick={handleSaveAndAdd} - ref={addButtonRef} - > - - - - - - - )} - - {data > 0 - ? orderBy( - uniqBy( - realData?.map((childData, index) => ({ - id: childData["@id"], - childData, - index, - })), - "id", - ), - "id", - ).map(({ id: expandID, childData, index }: any, count) => { - const childPath = composePaths(path, `${index}`); - return ( - {}} - rootSchema={rootSchema} - entityIRI={expandID} - data={childData} - key={expandID} - index={index} - count={count} - path={childPath} - imagePath={appliedUiSchemaOptions.imagePath} - elementDetailItemPath={ - appliedUiSchemaOptions.elementDetailItemPath - } - childLabelTemplate={ - appliedUiSchemaOptions.elementLabelTemplate - } - elementLabelProp={ - appliedUiSchemaOptions.elementLabelProp || "label" - } - formsPath={formsPath} - /> - ); - }) - : null} - -
- ); -}; - -export const MaterialArrayLayout = memo(MaterialArrayLayoutComponent); diff --git a/apps/exhibition-live/components/renderer/MaterialArrayOfLinkedItemRenderer.tsx b/apps/exhibition-live/components/renderer/MaterialArrayOfLinkedItemRenderer.tsx deleted file mode 100644 index ba4a19c1..00000000 --- a/apps/exhibition-live/components/renderer/MaterialArrayOfLinkedItemRenderer.tsx +++ /dev/null @@ -1,87 +0,0 @@ -/* - The MIT License - - Copyright (c) 2017-2019 EclipseSource Munich - https://github.com/eclipsesource/jsonforms - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*/ -import { - ArrayLayoutProps, - isObjectArrayWithNesting, - RankedTester, - rankWith, -} from "@jsonforms/core"; -import { withJsonFormsArrayLayoutProps } from "@jsonforms/react"; -import { Hidden } from "@mui/material"; -import React, { useCallback } from "react"; - -import { MaterialArrayLayout } from "./MaterialArrayLayout"; - -export const MaterialArrayOfLinkedItemRenderer = ({ - visible, - enabled, - id, - uischema, - schema, - label, - rootSchema, - renderers, - cells, - data, - path, - errors, - uischemas, - addItem, - removeItems, - translations, -}: ArrayLayoutProps) => { - const addItemCb = useCallback( - (p: string, value: any) => addItem(p, value), - [addItem], - ); - return ( - - - - ); -}; - -export const materialArrayLayoutTester: RankedTester = rankWith( - 4, - isObjectArrayWithNesting, -); -export default withJsonFormsArrayLayoutProps(MaterialArrayOfLinkedItemRenderer); diff --git a/apps/exhibition-live/components/renderer/MaterialDateRenderer.tsx b/apps/exhibition-live/components/renderer/MaterialDateRenderer.tsx deleted file mode 100644 index 99c41d8e..00000000 --- a/apps/exhibition-live/components/renderer/MaterialDateRenderer.tsx +++ /dev/null @@ -1,110 +0,0 @@ -import { - ControlProps, - isDateControl, - isDescriptionHidden, - RankedTester, - rankWith, -} from "@jsonforms/core"; -import { - createOnChangeHandler, - getData, - useFocus, -} from "@jsonforms/material-renderers"; -import { withJsonFormsControlProps } from "@jsonforms/react"; -import { DatePicker, LocalizationProvider } from "@mui/lab"; -import AdapterDayjs from "@mui/lab/AdapterDayjs"; -import { FormHelperText, Hidden, TextField } from "@mui/material"; -import merge from "lodash/merge"; -import React, { useMemo } from "react"; -import { useTranslation } from "next-i18next"; - -export const MaterialDateControl = (props: ControlProps) => { - const [focused, onFocus, onBlur] = useFocus(); - const { - description, - id, - errors, - label, - uischema, - visible, - enabled, - required, - path, - handleChange, - data, - config, - } = props; - const isValid = errors.length === 0; - const appliedUiSchemaOptions = merge({}, config, uischema.options); - const showDescription = !isDescriptionHidden( - visible, - description, - focused, - appliedUiSchemaOptions.showUnfocusedDescription, - ); - - const { t } = useTranslation(); - const format = appliedUiSchemaOptions.dateFormat ?? t("date_format"); - const saveFormat = appliedUiSchemaOptions.dateSaveFormat ?? "YYYY-MM-DD"; - - const firstFormHelperText = showDescription - ? description - : !isValid - ? errors - : null; - const secondFormHelperText = showDescription && !isValid ? errors : null; - const onChange = useMemo( - () => createOnChangeHandler(path, handleChange, saveFormat), - [path, handleChange, saveFormat], - ); - - return ( - - - d && onChange(d)} - inputFormat={format} - disableMaskedInput - views={appliedUiSchemaOptions.views} - disabled={!enabled} - cancelText={appliedUiSchemaOptions.cancelLabel} - clearText={appliedUiSchemaOptions.clearLabel} - okText={appliedUiSchemaOptions.okLabel} - // @ts-ignore - renderInput={(params) => ( - - )} - /> - - {firstFormHelperText} - - {secondFormHelperText} - - - ); -}; - -export const materialDateControlTester: RankedTester = rankWith( - 6, - isDateControl, -); - -export default withJsonFormsControlProps(MaterialDateControl); diff --git a/apps/exhibition-live/components/renderer/MaterialGroupLayout.tsx b/apps/exhibition-live/components/renderer/MaterialGroupLayout.tsx deleted file mode 100644 index f6a9278b..00000000 --- a/apps/exhibition-live/components/renderer/MaterialGroupLayout.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import { - getSchema, - getTranslator, - GroupLayout, - JsonFormsState, - LayoutProps, - RankedTester, - rankWith, - Resolve, - uiTypeIs, - withIncreasedRank, -} from "@jsonforms/core"; -import { - MaterialLayoutRenderer, - MaterialLayoutRendererProps, -} from "@jsonforms/material-renderers"; -import { useJsonForms, withJsonFormsLayoutProps } from "@jsonforms/react"; -import { - Card, - CardContent, - CardHeader, - FormHelperText, - Grid, - Hidden, -} from "@mui/material"; -import isEmpty from "lodash/isEmpty"; -import React, { useMemo } from "react"; -import rehypeExternalLinks from "rehype-external-links"; -import rehypeSanitize from "rehype-sanitize"; - -import { getI18nDescription, getI18nLabel } from "./i18nHelper"; -import { MDEditorMarkdown } from "./MDEditor"; -import { memo } from "./config"; - -export const groupTester: RankedTester = rankWith(1, uiTypeIs("Group")); -const style: { [x: string]: any } = { marginBottom: "10px" }; - -const GroupComponent = memo( - ({ - visible, - enabled, - uischema, - state, - path, - schema, - ...props - }: MaterialLayoutRendererProps & { state: JsonFormsState }) => { - const groupLayout = uischema as GroupLayout; - const rootSchema = getSchema(state); - const translator = getTranslator()(state); - const resolvedSchema = Resolve.schema( - schema || rootSchema, - `#/properties/${groupLayout.label}`, - rootSchema, - ); - const i18nLabel = - path && - getI18nLabel( - groupLayout.label || null, - translator, - groupLayout, - `${path}.${groupLayout.label}`, - resolvedSchema, - ); - const i18nDescription = - path && - getI18nDescription( - null, - translator, - groupLayout, - `${path}.${groupLayout.label}`, - resolvedSchema, - ); - const rehypePlugins = useMemo( - () => [[rehypeSanitize], [rehypeExternalLinks, { target: "_blank" }]], - [], - ); - return ( - - - {!isEmpty(i18nLabel) && } - - {i18nDescription && i18nDescription.length > 0 && ( - - - - - - - - )} - - - - - ); - }, -); - -export const MaterializedGroupLayoutRenderer = ({ - uischema, - schema, - path, - visible, - enabled, - renderers, - cells, - direction, -}: LayoutProps) => { - const groupLayout = uischema as GroupLayout; - const ctx = useJsonForms(); - const state = { jsonforms: ctx }; - return ( - - ); -}; - -export default withJsonFormsLayoutProps(MaterializedGroupLayoutRenderer); - -export const materialGroupTester: RankedTester = withIncreasedRank( - 5, - groupTester, -); diff --git a/apps/exhibition-live/components/renderer/PrimaryFieldTextRenderer.tsx b/apps/exhibition-live/components/renderer/PrimaryFieldTextRenderer.tsx index a28c93e2..650772e1 100644 --- a/apps/exhibition-live/components/renderer/PrimaryFieldTextRenderer.tsx +++ b/apps/exhibition-live/components/renderer/PrimaryFieldTextRenderer.tsx @@ -1,10 +1,18 @@ import React, { useCallback, useState } from "react"; -import { CellProps, scopeEndsWith, WithClassname } from "@jsonforms/core"; import { + CellProps, + isDescriptionHidden, + scopeEndsWith, + showAsRequired, + WithClassname, +} from "@jsonforms/core"; +import { + FormControl, + FormHelperText, IconButton, - Input, InputAdornment, InputBaseComponentProps, + InputLabel, InputProps, useTheme, } from "@mui/material"; @@ -12,8 +20,8 @@ import merge from "lodash/merge"; import Close from "@mui/icons-material/Close"; import { JsonFormsTheme, - MaterialInputControl, useDebouncedChange, + useFocus, } from "@jsonforms/material-renderers"; import { ControlProps, @@ -23,135 +31,208 @@ import { and, } from "@jsonforms/core"; import { withJsonFormsControlProps } from "@jsonforms/react"; -import { primaryFields, typeIRItoTypeName } from "../config"; import { + useAdbContext, useGlobalSearch, useKeyEventForSimilarityFinder, useRightDrawerState, - useSimilarityFinderState, -} from "../state"; +} from "@slub/edb-state-hooks"; +import { primaryFields } from "@slub/exhibition-schema"; +import { useInputComponent, useInputVariant } from "./helper"; interface MuiTextInputProps { muiInputProps?: InputProps["inputProps"]; inputComponent?: InputProps["inputComponent"]; } -export const PrimaryFieldText = React.memo( - (props: CellProps & WithClassname & MuiTextInputProps) => { - const [showAdornment, setShowAdornment] = useState(false); - const { - data, - config, - className, - id, - enabled, - uischema, - isValid, - path, - handleChange, - schema, - muiInputProps, - inputComponent, - } = props; - const maxLength = schema.maxLength; - const appliedUiSchemaOptions = merge({}, config, uischema.options); - let inputProps: InputBaseComponentProps; - if (appliedUiSchemaOptions.restrict) { - inputProps = { maxLength: maxLength }; - } else { - inputProps = {}; - } - - inputProps = merge(inputProps, muiInputProps); - - if (appliedUiSchemaOptions.trim && maxLength !== undefined) { - inputProps.size = maxLength; - } - - const [inputText, onChange, onClear] = useDebouncedChange( - handleChange, - "", - data, - path, - ); - const onPointerEnter = () => setShowAdornment(true); - const onPointerLeave = () => setShowAdornment(false); - - const theme: JsonFormsTheme = useTheme(); - - const closeStyle = { - background: - theme.jsonforms?.input?.delete?.background || - theme.palette.background.default, - borderRadius: "50%", - }; - - const { setOpen: setRightDrawerOpen } = useRightDrawerState(); - - const { setPath, setTypeName } = useGlobalSearch(); - const handleFocus = useCallback(() => { - if (!config?.typeIRI || !config.formsPath) return; - setPath(config.formsPath); - setTypeName(typeIRItoTypeName(config.typeIRI as string)); - setRightDrawerOpen(true); - }, [ - config?.typeIRI, - config?.formsPath, - setPath, - setTypeName, - setRightDrawerOpen, - ]); - - const handleKeyUp = useKeyEventForSimilarityFinder(); - - return ( - <> - { + const { typeIRIToTypeName } = useAdbContext(); + const [showAdornment, setShowAdornment] = useState(false); + const { + data, + config, + className, + id, + enabled, + uischema, + isValid, + path, + handleChange, + schema, + muiInputProps, + inputComponent, + } = props; + const maxLength = schema.maxLength; + const appliedUiSchemaOptions = merge({}, config, uischema.options); + let inputProps: InputBaseComponentProps; + if (appliedUiSchemaOptions.restrict) { + inputProps = { maxLength: maxLength }; + } else { + inputProps = {}; + } + + inputProps = merge(inputProps, muiInputProps); + + if (appliedUiSchemaOptions.trim && maxLength !== undefined) { + inputProps.size = maxLength; + } + + const [inputText, onChange, onClear] = useDebouncedChange( + handleChange, + "", + data, + path, + ); + const onPointerEnter = () => setShowAdornment(true); + const onPointerLeave = () => setShowAdornment(false); + + const theme: JsonFormsTheme = useTheme(); + + const closeStyle = { + background: + theme.jsonforms?.input?.delete?.background || + theme.palette.background.default, + borderRadius: "50%", + }; + + const { setOpen: setRightDrawerOpen } = useRightDrawerState(); + + const { setPath, setTypeName } = useGlobalSearch(); + const handleFocus = useCallback(() => { + if (!config?.typeIRI || !config.formsPath) return; + setPath(config.formsPath); + setTypeName(typeIRIToTypeName(config.typeIRI as string)); + setRightDrawerOpen(true); + }, [ + config?.typeIRI, + config?.formsPath, + typeIRIToTypeName, + setPath, + setTypeName, + setRightDrawerOpen, + ]); + + const handleKeyUp = useKeyEventForSimilarityFinder(); + const InputComponent = useInputComponent(); + + return ( + - - - - - } - inputComponent={inputComponent} - /> - - ); - }, -); + > + + + + + } + inputComponent={inputComponent} + /> + ); +}; + +export interface WithInput { + input: any; +} + +const MaterialInputControl = (props: ControlProps & WithInput) => { + const [focused, onFocus, onBlur] = useFocus(); + const { + id, + description, + errors, + label, + uischema, + visible, + required, + config, + input, + } = props; + const variant = useInputVariant(); + const isValid = errors.length === 0; + const appliedUiSchemaOptions = merge({}, config, uischema.options); + + const showDescription = !isDescriptionHidden( + visible, + description, + focused, + appliedUiSchemaOptions.showUnfocusedDescription, + ); + + const firstFormHelperText = showDescription + ? description + : !isValid + ? errors + : null; + const secondFormHelperText = showDescription && !isValid ? errors : null; + const InnerComponent = input; + + if (!visible) { + return null; + } + + return ( + + + {label} + + + + {firstFormHelperText} + + {secondFormHelperText} + + ); +}; const PrimaryTextField = (props: ControlProps) => ( @@ -162,7 +243,7 @@ export const primaryTextFieldControlTester: ( ) => RankedTester = (typeName) => rankWith( 10, - and(isStringControl, scopeEndsWith(primaryFields[typeName].label)), + and(isStringControl, scopeEndsWith("/" + primaryFields[typeName]?.label)), ); export const PrimaryTextFieldRenderer = withJsonFormsControlProps(PrimaryTextField); diff --git a/apps/exhibition-live/components/renderer/SelectListWithChipsRenderer.tsx b/apps/exhibition-live/components/renderer/SelectListWithChipsRenderer.tsx deleted file mode 100644 index 6eccc3b6..00000000 --- a/apps/exhibition-live/components/renderer/SelectListWithChipsRenderer.tsx +++ /dev/null @@ -1,189 +0,0 @@ -import { ArrayLayoutProps } from "@jsonforms/core"; -import { Cancel, Close } from "@mui/icons-material"; -import { - Checkbox, - Chip, - Fab, - FormControl, - Hidden, - InputLabel, - ListItemText, - MenuItem, - Select, - SelectChangeEvent, - useMediaQuery, -} from "@mui/material"; -import { createStyles, makeStyles } from "@mui/styles"; -import _ from "lodash"; -import React, { useCallback, useEffect, useState } from "react"; - -import { i18nHelper } from "./i18nHelper"; -import { - ArrayDataProp, - withJsonFormsArrayLayoutProps, -} from "./withJsonFormsArrayLayoutProps"; - -type CustomArrayLayoutProps = ArrayLayoutProps & ArrayDataProp; -const useStyles = makeStyles((theme: { spacing: (x: number) => number }) => - createStyles({ - formControl: { - margin: theme.spacing(1), - minWidth: 120, - maxWidth: "100%", - }, - chips: { - display: "flex", - flexWrap: "wrap", - }, - chip: { - margin: 2, - }, - noLabel: { - marginTop: theme.spacing(3), - }, - }), -); -type SelectListOptions = { label: string; value: string; key: string }; - -const buildItemsEnumKey = (key: string) => `items.enum.${key}.label`; - -const SelectListWithChipsRenderer = ({ - removeItems, - addItem, - visible, - schema, - arrayData: values = [], - path, - label, - uischema, - translator, -}: CustomArrayLayoutProps) => { - const [selectOpen, setSelectOpen] = useState(false); - const isMobile = useMediaQuery("(max-width:800px)"); - const classes = useStyles(); - - const [enumLabels, setEnumLabels] = useState<{ [k: string]: string }>({}); - const [options, setOptions] = useState([]); - - useEffect(() => { - if (!Array.isArray(schema?.enum)) return; - setEnumLabels( - Object.fromEntries( - schema.enum.map((key) => [ - key, - i18nHelper( - buildItemsEnumKey(key), - key, - translator, - uischema, - path, - schema, - ), - ]), - ), - ); - setOptions( - schema.enum.map((key) => ({ - key: key as string, - value: key, - label: - i18nHelper( - buildItemsEnumKey(key), - key, - translator, - uischema, - path, - schema, - ) || key, - })), - ); - }, [setEnumLabels, setOptions, translator, uischema, path, schema]); - - const handleChange = useCallback( - ({ target: { value: targetValues } }: SelectChangeEvent) => { - const diff = _.xor(values, targetValues); - if (targetValues.length > values.length) { - diff.forEach((item) => addItem(path, item)()); - } else { - diff.forEach((item) => { - const i = values.indexOf(item); - i >= 0 && removeItems && removeItems(path, [i])(); - }); - } - }, - [path, addItem, removeItems, values], - ); - - const handleDelete = useCallback( - (_: any, value: string) => { - const i = values.indexOf(value); - i >= 0 && removeItems && removeItems(path, [i])(); - }, - [removeItems, values, path], - ); - - return ( - - - - {label} - - { - - } - {isMobile && selectOpen && ( - setSelectOpen(false)} - > - - - )} - - - ); -}; - -export default withJsonFormsArrayLayoutProps(SelectListWithChipsRenderer); diff --git a/apps/exhibition-live/components/renderer/SelectListWithDetailMasterItem.tsx b/apps/exhibition-live/components/renderer/SelectListWithDetailMasterItem.tsx deleted file mode 100644 index 2908edca..00000000 --- a/apps/exhibition-live/components/renderer/SelectListWithDetailMasterItem.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { withJsonFormsContext } from "@jsonforms/react"; -import { Avatar, ListItem, ListItemAvatar, ListItemText } from "@mui/material"; -import React from "react"; - -import { StatePropsOfMasterItem } from "./ListWithDetailMasterItem"; -import { withContextToMasterListItemProps } from "./withContextToMasterListItem"; - -const SelectListWithDetailMasterItem = ({ - index, - childLabel, -}: StatePropsOfMasterItem) => { - return ( - - - {index + 1} - - - - ); -}; - -export default withJsonFormsContext( - withContextToMasterListItemProps(SelectListWithDetailMasterItem), -); diff --git a/apps/exhibition-live/components/renderer/ValidationIcon.tsx b/apps/exhibition-live/components/renderer/ValidationIcon.tsx deleted file mode 100644 index 8bcfe227..00000000 --- a/apps/exhibition-live/components/renderer/ValidationIcon.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline"; -import { Badge, styled, Tooltip } from "@mui/material"; -import React from "react"; - -const StyledBadge = styled(Badge)(({ theme }: any) => ({ - color: theme.palette.error.main, -})); - -export interface ValidationProps { - errorMessages: string; - id: string; -} - -const ValidationIcon: React.FC = ({ errorMessages, id }) => { - return ( - - - - - - ); -}; - -export default ValidationIcon; diff --git a/apps/exhibition-live/components/renderer/helper.ts b/apps/exhibition-live/components/renderer/helper.ts new file mode 100644 index 00000000..987b1997 --- /dev/null +++ b/apps/exhibition-live/components/renderer/helper.ts @@ -0,0 +1,35 @@ +import { + FilledInput, + Input, + InputBaseProps, + OutlinedInput, + TextFieldProps, + useThemeProps, +} from "@mui/material"; + +export interface WithInputProps { + label?: string; +} + +const variantToInput = { + standard: Input, + filled: FilledInput, + outlined: OutlinedInput, +}; + +export const defaultInputVariant: TextFieldProps["variant"] = "standard"; + +export function useInputVariant(): TextFieldProps["variant"] { + const { variant = defaultInputVariant } = useThemeProps({ + props: {} as TextFieldProps, + name: "MuiTextField", + }); + return variant; +} + +export function useInputComponent(): React.JSXElementConstructor< + InputBaseProps & WithInputProps +> { + const variant = useInputVariant(); + return variantToInput[variant] ?? variantToInput[defaultInputVariant]; +} diff --git a/apps/exhibition-live/components/renderer/index.ts b/apps/exhibition-live/components/renderer/index.ts index 37c07820..e06b73ee 100644 --- a/apps/exhibition-live/components/renderer/index.ts +++ b/apps/exhibition-live/components/renderer/index.ts @@ -1,17 +1 @@ -export * from "./ArrayToolbar"; -export * from "./DeleteDialog"; -export * from "./EnumRenderer"; -export * from "./i18nHelper"; -export * from "./ListWithDetailMasterItem"; -export * from "./MarkdownTextFieldRenderer"; -export * from "./MaterialDateRenderer"; -export * from "./MaterialGroupLayout"; -export * from "./MaterialArrayOfLinkedItemChipsRenderer"; -export * from "./MaterialArrayOfLinkedItemRenderer"; -export * from "./MDEditor"; -export * from "./SelectListWithChipsRenderer"; -export * from "./SelectListWithDetailMasterItem"; -export * from "./ValidationIcon"; -export * from "./withContextToMasterListItem"; -export * from "./withJsonFormsArrayLayoutProps"; export * from "./PrimaryFieldTextRenderer"; diff --git a/apps/exhibition-live/components/renderer/withContextToMasterListItem.tsx b/apps/exhibition-live/components/renderer/withContextToMasterListItem.tsx deleted file mode 100644 index ff9ad6e8..00000000 --- a/apps/exhibition-live/components/renderer/withContextToMasterListItem.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import { - composePaths, - getData, - JsonFormsState, - Resolve, -} from "@jsonforms/core"; -import { JsonFormsStateContext } from "@jsonforms/react"; -import find from "lodash/find"; -import React, { ComponentType } from "react"; - -import { filterUndefOrNull, resolveObj } from "../utils/core"; -import { - OwnPropsOfMasterListItem, - StatePropsOfMasterItem, -} from "./ListWithDetailMasterItem"; - -export const mapStateToMasterListItemProps = ( - state: JsonFormsState, - ownProps: OwnPropsOfMasterListItem, -): StatePropsOfMasterItem => { - const { schema, path, index, uischema } = ownProps; - /*const foundUISchema = findUISchema( - state.jsonforms.uischemas, - schema, - uischema.scope, - path - ) - console.log({foundUISchema})*/ - const findFirstPrimitiveProp = () => - schema.properties - ? find(Object.keys(schema.properties), (propName) => { - // @ts-ignore - const prop = schema.properties[propName]; - return ( - prop.type === "string" || - prop.type === "number" || - prop.type === "integer" - ); - }) - : undefined; - const labelProp: any = - uischema.options?.elementLabelProp || findFirstPrimitiveProp(); - const labelJoint = uischema.options?.elementLabelJoint || " "; - const childPath = composePaths(path, `${index}`); - const childData = Resolve.data(getData(state), childPath); - let childLabel; - if (Array.isArray(labelProp)) { - childLabel = filterUndefOrNull( - labelProp.map( - (prop) => - typeof prop === "string" && resolveObj(childData, prop, undefined), - ), - ).join(labelJoint); - } else { - childLabel = labelProp ? childData[labelProp] : ""; - } - - return { - ...ownProps, - childLabel: childLabel, - }; -}; - -export const ctxToMasterListItemProps = ( - ctx: JsonFormsStateContext, - ownProps: OwnPropsOfMasterListItem, -) => mapStateToMasterListItemProps({ jsonforms: { ...ctx } }, ownProps); - -export const withContextToMasterListItemProps = - // @ts-ignore - - - ( - Component: ComponentType, - ): ComponentType => - ({ ctx, props }: JsonFormsStateContext & StatePropsOfMasterItem) => { - const stateProps = ctxToMasterListItemProps(ctx, props); - return ; - }; diff --git a/apps/exhibition-live/components/renderer/withJsonFormsArrayLayoutProps.tsx b/apps/exhibition-live/components/renderer/withJsonFormsArrayLayoutProps.tsx deleted file mode 100644 index 96f9662a..00000000 --- a/apps/exhibition-live/components/renderer/withJsonFormsArrayLayoutProps.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { - ArrayLayoutProps, - composeWithUi, - ControlElement, - getData, - getTranslator, - OwnPropsOfControl, - Resolve, - Translator, -} from "@jsonforms/core"; -import { - ctxDispatchToArrayControlProps, - ctxToArrayLayoutProps, - JsonFormsStateContext, - withJsonFormsContext, -} from "@jsonforms/react"; -import React, { ComponentType, FunctionComponent } from "react"; -import { memo } from "./config"; - -export type ArrayDataProp = { - translator: Translator; - arrayData: any[]; - uischema?: ControlElement; -}; -export type CustomArrayLayoutProps = ArrayLayoutProps & ArrayDataProp; - -const withContextToArrayLayoutProps = - ( - Component: ComponentType, - ): ComponentType => - ({ ctx, props }: JsonFormsStateContext & ArrayLayoutProps) => { - const arrayLayoutProps = ctxToArrayLayoutProps(ctx, props); - const state = { jsonforms: ctx }; - const rootData = getData(state); - const translator = getTranslator()(state); - const path = composeWithUi(props.uischema, props.path); - const data = Resolve.data(rootData, path); - const dispatchProps = ctxDispatchToArrayControlProps(ctx.dispatch); - return ( - - ); - }; - -export const withJsonFormsArrayLayoutProps = ( - Component: FunctionComponent, - memoize = true, -): ComponentType => - withJsonFormsContext( - withContextToArrayLayoutProps(memoize ? memo(Component) : Component), - ); diff --git a/apps/exhibition-live/components/state/index.ts b/apps/exhibition-live/components/state/index.ts index 9b9f2cb6..4e43b63b 100644 --- a/apps/exhibition-live/components/state/index.ts +++ b/apps/exhibition-live/components/state/index.ts @@ -1,19 +1,4 @@ -export * from "./useFormData"; -export * from "./useFormEditor"; -export * from "./useGlobalSearch"; -export * from "./useGlobalSearchWithHelper"; -export * from "./useLocalHistory"; -export * from "./useOxigraph"; -export * from "./useRDFDataSources"; -export * from "./useThemeSettings"; -export * from "./useQueryKeyResolver"; export * from "./useGlobalAuth"; -export * from "./useDrawerDimensions"; -export * from "./useRightDrawerState"; -export * from "./useTypeIRIFromEntity"; -export * from "./useSimilarityFinderState"; -export * from "./useLoadQuery"; -export * from "./useKeyEventForSimilarityFinder"; -export * from "./useModalRegistry"; -export * from "./useGlobalSettings"; -export * from "./useDataStore"; +export * from "./useThemeSettings"; +export * from "./useOptionalLiveDemoEndpoint"; +export * from "./useThemeSettings"; diff --git a/apps/exhibition-live/components/state/useDataStore.ts b/apps/exhibition-live/components/state/useDataStore.ts deleted file mode 100644 index 428312f0..00000000 --- a/apps/exhibition-live/components/state/useDataStore.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { AbstractDatastore } from "@slub/edb-global-types"; -import { initSPARQLStore } from "@slub/sparql-db-impl"; -import { JSONSchema7 } from "json-schema"; -import { useGlobalCRUDOptions } from "./useGlobalCRUDOptions"; -import { useGlobalSettings } from "./useGlobalSettings"; -import { CRUDFunctions } from "@slub/edb-core-types"; -import { sladb } from "../form/formConfigs"; -import { useMemo } from "react"; -import { WalkerOptions } from "@slub/edb-graph-traversal"; - -type UserDataStoreProps = { - crudOptionsPartial?: Partial; - schema: JSONSchema7; - walkerOptions?: Partial; -}; - -type UseDataStoreState = { - dataStore: AbstractDatastore; - ready: boolean; -}; - -export const typeNameToTypeIRI = (typeName: string) => sladb(typeName).value; -export const useDataStore = ({ - crudOptionsPartial = {}, - schema, - walkerOptions, -}: UserDataStoreProps): UseDataStoreState => { - const { crudOptions: globalCRUDOptions } = useGlobalCRUDOptions(); - const crudOptions = useMemo( - () => ({ ...globalCRUDOptions, ...crudOptionsPartial }), - [globalCRUDOptions, crudOptionsPartial], - ); - - const { defaultPrefix, namespacePrefixes } = useGlobalSettings(); - const dataStore = useMemo( - () => - crudOptions.constructFetch && - initSPARQLStore({ - defaultPrefix, - typeNameToTypeIRI, - queryBuildOptions: namespacePrefixes, - walkerOptions, - sparqlQueryFunctions: crudOptions, - schema, - defaultLimit: 10, - }), - [crudOptions, defaultPrefix, namespacePrefixes, walkerOptions, schema], - ); - - return { - dataStore, - ready: Boolean(dataStore), - }; -}; diff --git a/apps/exhibition-live/components/state/useExtendedSchema.ts b/apps/exhibition-live/components/state/useExtendedSchema.ts deleted file mode 100644 index cb71225e..00000000 --- a/apps/exhibition-live/components/state/useExtendedSchema.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { JSONSchema7 } from "json-schema"; -import { useMemo } from "react"; - -import schema from "../../public/schema/Exhibition.schema.json"; -import genSlubJSONLDSemanticProperties from "../form/genSlubJSONLDSemanticProperties"; -import { prepareStubbedSchema } from "@slub/json-schema-utils"; - -type UseExtendedSchemaProps = { - typeName: string; - classIRI: string; -}; - -const genSlubRequiredProperties = (_modelName: string) => { - return ["@type", "@id"]; -}; - -const useExtendedSchema = ({ typeName, classIRI }: UseExtendedSchemaProps) => { - //const {data: loadedSchema} = useQuery(['schema', typeName], () => fetch(`/schema/${typeName}.schema.json`).then(async res => { - return useMemo(() => { - const prepared = prepareStubbedSchema( - schema as JSONSchema7, - genSlubJSONLDSemanticProperties, - genSlubRequiredProperties, - { - excludeType: [ - "InvolvedPerson", - "InvolvedCorporation", - "AuthorityEntry", - ], - excludeSemanticPropertiesForType: ["AuthorityEntry"], - }, - ); - const defsFieldName = prepared.definitions ? "definitions" : "$defs"; - const specificModel = - (prepared[defsFieldName]?.[typeName] as object | undefined) || {}; - const finalSchema = { - ...(typeof prepared === "object" ? prepared : {}), - ...specificModel, - }; - return finalSchema; - }, [typeName]); -}; - -export default useExtendedSchema; diff --git a/apps/exhibition-live/components/state/useGlobalAuth.ts b/apps/exhibition-live/components/state/useGlobalAuth.ts index 7741c3e0..fa0bba40 100644 --- a/apps/exhibition-live/components/state/useGlobalAuth.ts +++ b/apps/exhibition-live/components/state/useGlobalAuth.ts @@ -1,10 +1,7 @@ -import { - editorPermissions, - fullPermission, - noPermission, - Permission, -} from "../config"; +import { fullPermission, noPermission } from "@slub/edb-core-utils"; import { create } from "zustand"; +import { Permission } from "@slub/edb-core-types"; +import { editorPermissions } from "../config"; export enum RoleType { Admin = "admin", diff --git a/apps/exhibition-live/components/state/useGlobalSettings.ts b/apps/exhibition-live/components/state/useGlobalSettings.ts deleted file mode 100644 index 7c84417c..00000000 --- a/apps/exhibition-live/components/state/useGlobalSettings.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { JsonLdContext } from "jsonld-context-parser"; -import { create } from "zustand"; -import { - defaultJsonldContext, - defaultPrefix, - defaultQueryBuilderOptions, -} from "../form/formConfigs"; -import { NamespaceBuilderPrefixes } from "@slub/edb-core-types"; - -export type UseGlobalSettingsState = { - defaultPrefix: string; - jsonldContext?: JsonLdContext; - namespacePrefixes: NamespaceBuilderPrefixes; - allowUnsafeSourceIRIs?: boolean; -}; - -export const useGlobalSettings = create(() => ({ - defaultPrefix: defaultPrefix, - jsonldContext: defaultJsonldContext, - namespacePrefixes: defaultQueryBuilderOptions, - allowUnsafeSourceIRIs: false, -})); diff --git a/apps/exhibition-live/components/state/useLoadQuery.ts b/apps/exhibition-live/components/state/useLoadQuery.ts deleted file mode 100644 index 30131720..00000000 --- a/apps/exhibition-live/components/state/useLoadQuery.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { CRUDOptions } from "./useSPARQL_CRUD"; -import { useGlobalCRUDOptions } from "./useGlobalCRUDOptions"; -import { useQueryClient } from "@tanstack/react-query"; -import { useCallback } from "react"; -import { JSONSchema7 } from "json-schema"; -import { load } from "@slub/sparql-schema"; -import { defaultQueryBuilderOptions } from "../form/formConfigs"; - -export const useLoadQuery = ( - defaultPrefix: string, - queryKey: string = "load", - crudOptionsPart: Partial = {}, -) => { - const { crudOptions: globalCRUDOptions } = useGlobalCRUDOptions(); - const crudOptions = { ...globalCRUDOptions, ...crudOptionsPart }; - const { constructFetch } = crudOptions || {}; - const queryClient = useQueryClient(); - - const loadEntity = useCallback( - async (entityIRI: string, typeIRI: string, schema: JSONSchema7) => { - return queryClient.fetchQuery( - [queryKey, typeIRI, entityIRI], - async () => { - if (!entityIRI || !constructFetch) return null; - const res = await load(entityIRI, typeIRI, schema, constructFetch, { - defaultPrefix, - queryBuildOptions: defaultQueryBuilderOptions, - }); - return res; - }, - ); - }, - [constructFetch, defaultPrefix, queryKey, queryClient], - ); - - return loadEntity; -}; diff --git a/apps/exhibition-live/components/state/useModalRegistry.ts b/apps/exhibition-live/components/state/useModalRegistry.ts deleted file mode 100644 index 84c6cc6d..00000000 --- a/apps/exhibition-live/components/state/useModalRegistry.ts +++ /dev/null @@ -1,19 +0,0 @@ -import NiceModal, { NiceModalHocProps } from "@ebay/nice-modal-react"; -import { FC } from "react"; -import { create } from "zustand"; - -type UseModalRegistryType = { - modalRegistry: Set; - registerModal: (modalName: string, element: FC) => void; -}; - -export const useModalRegistry = create((set, get) => ({ - modalRegistry: new Set(), - registerModal: (modalName, element) => { - if (get().modalRegistry.has(modalName)) { - return; - } - NiceModal.register(modalName, element); - get().modalRegistry.add(modalName); - }, -})); diff --git a/apps/exhibition-live/components/state/useOptionalLiveDemoEndpoint.ts b/apps/exhibition-live/components/state/useOptionalLiveDemoEndpoint.ts index d7b37bae..3f5a6336 100644 --- a/apps/exhibition-live/components/state/useOptionalLiveDemoEndpoint.ts +++ b/apps/exhibition-live/components/state/useOptionalLiveDemoEndpoint.ts @@ -1,13 +1,15 @@ import { useEffect } from "react"; -import { SparqlEndpoint, useSettings } from "./useLocalSettings"; +import { SparqlEndpoint } from "@slub/edb-core-types"; +import { useSettings } from "@slub/edb-state-hooks"; /** * This hook adds a demo endpoint to the list of endpoints if the app is not running on the test server. * It is used to provide an open database connection for the live demo. */ export const useOptionalLiveDemoEndpoint = () => { - const { sparqlEndpoints, setSparqlEndpoints } = useSettings(); + const { sparqlEndpoints, setSparqlEndpoints, lockedEndpoint } = useSettings(); useEffect(() => { + if (lockedEndpoint) return; const demoEndpointURI = "https://ausstellungsdatenbank.kuenste.live/query"; if ( window.location.hostname !== "sdv-ahn-adbtest.slub-dresden.de" && @@ -27,5 +29,14 @@ export const useOptionalLiveDemoEndpoint = () => { }; setSparqlEndpoints([liveDemoTestDatabase, ...otherEndpoints]); } - }, [sparqlEndpoints, setSparqlEndpoints]); + }, [sparqlEndpoints, setSparqlEndpoints, lockedEndpoint]); +}; + +export const OptionalLiveDemoEndpoint = ({ + children, +}: { + children: React.ReactNode; +}) => { + useOptionalLiveDemoEndpoint(); + return children; }; diff --git a/apps/exhibition-live/components/state/useOxigraph.ts b/apps/exhibition-live/components/state/useOxigraph.ts deleted file mode 100644 index c65bf7c4..00000000 --- a/apps/exhibition-live/components/state/useOxigraph.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { AsyncOxigraph } from "async-oxigraph"; -import { create } from "zustand"; -import { PUBLIC_BASE_PATH } from "../config"; - -const initAsyncOxigraph = async function () { - const ao = new AsyncOxigraph(PUBLIC_BASE_PATH + "/worker.js"); - await ao.init(PUBLIC_BASE_PATH + "/web_bg.wasm"); // Default is same folder as worker.js - return ao; -}; - -type OxigraphStore = { - oxigraph: { ao: AsyncOxigraph } | undefined; - init: () => void; - initialized: boolean; - bulkLoaded: boolean; - setBulkLoaded: (b: boolean) => void; -}; - -export const useOxigraph = create((set, get) => ({ - oxigraph: undefined, - bulkLoaded: false, - initialized: false, - init: async () => { - console.log("init oxigraph"); - if (get().initialized) return; - set({ initialized: true }); - console.log("really init oxigraph"); - const ao = await initAsyncOxigraph(); - console.log({ ao }); - set({ oxigraph: { ao } }); - }, - setBulkLoaded: (b) => set({ bulkLoaded: b }), -})); diff --git a/apps/exhibition-live/components/state/useRDFDataSources.ts b/apps/exhibition-live/components/state/useRDFDataSources.ts deleted file mode 100644 index 271a6938..00000000 --- a/apps/exhibition-live/components/state/useRDFDataSources.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { useQueries, useQuery } from "@tanstack/react-query"; -import { RDFMimetype } from "async-oxigraph"; -import { useCallback, useEffect, useState } from "react"; - -import { BASE_IRI } from "../config"; -import { useOxigraph } from "./useOxigraph"; - -export const useRDFDataSources = (source: string) => { - const { oxigraph, init, bulkLoaded, setBulkLoaded } = useOxigraph(); - const [bulkLoading, setBulkLoading] = useState(false); - const { data } = useQuery(["exhibition", "ontology"], () => - fetch(source).then((r) => r.text()), - ); - - const load = useCallback( - async (ao: any) => { - setBulkLoading(true); - await ao.load(data, RDFMimetype.TURTLE, BASE_IRI); - setBulkLoading(false); - setBulkLoaded(true); - }, - [setBulkLoading, setBulkLoaded, data], - ); - - useEffect(() => { - if (!data) return; - if (oxigraph) { - load(oxigraph.ao); - } else { - init(); - } - }, [init, oxigraph, data, load]); - - return { - bulkLoading, - bulkLoaded, - }; -}; diff --git a/apps/exhibition-live/components/state/useSPARQL_CRUD.ts b/apps/exhibition-live/components/state/useSPARQL_CRUD.ts deleted file mode 100644 index 58868099..00000000 --- a/apps/exhibition-live/components/state/useSPARQL_CRUD.ts +++ /dev/null @@ -1,312 +0,0 @@ -import { Dataset } from "@rdfjs/types"; -import { - QueryObserverOptions, - QueryObserverResult, - useQuery, - useQueryClient, - UseQueryResult, -} from "@tanstack/react-query"; -import { - ASK, - CONSTRUCT, - DELETE, - INSERT, - SELECT, -} from "@tpluscode/sparql-builder"; -import { JSONSchema7 } from "json-schema"; -import jsonld from "jsonld"; -import N3 from "n3"; -import { useCallback, useEffect, useState } from "react"; -import { useSnackbar } from "notistack"; - -import { jsonSchemaGraphInfuser } from "../utils/graph/jsonSchemaGraphInfuser"; -import { jsonSchema2construct } from "../utils/sparql"; -import { useQueryKeyResolver } from "./useQueryKeyResolver"; -import df from "@rdfjs/data-model"; -import { CRUDFunctions, SparqlBuildOptions } from "@slub/edb-core-types"; -import { WalkerOptions } from "@slub/edb-graph-traversal"; - -type OwnUseCRUDResults = { - save: (data?: any) => Promise; - remove: () => Promise; - exists: () => Promise; - load: () => Promise; - reset: () => void; - getClassIRIs: (entityIRI?: string) => Promise; - isUpdate: boolean; - setIsUpdate: (isUpdate: boolean) => void; -}; - -export type UseCRUDResults = UseQueryResult & OwnUseCRUDResults; -export type CRUDOptions = CRUDFunctions & { - defaultPrefix: string; - data: any; - setData?: (data: any, isRefetch: boolean) => void; - walkerOptions?: Partial; - queryBuildOptions?: SparqlBuildOptions; - upsertByDefault?: boolean; - ready?: boolean; - onLoad?: (data: any) => void; - queryOptions?: QueryObserverOptions; - queryKey?: string; -}; - -export const useSPARQL_CRUD = ( - entityIRI: string | undefined, - typeIRI: string | undefined, - schema: JSONSchema7, - { - askFetch, - constructFetch, - selectFetch, - defaultPrefix, - updateFetch, - setData, - data, - walkerOptions = {}, - queryBuildOptions, - upsertByDefault, - onLoad, - queryOptions, - queryKey = "load", - }: CRUDOptions, -): UseCRUDResults => { - const [isUpdate, setIsUpdate] = useState(false); - const [whereEntity, setWhereEntity] = useState(); - const { updateSourceToTargets, removeSource, resolveSourceIRIs } = - useQueryKeyResolver(); - const [lastEntityLoaded, setLastEntityLoaded] = useState< - string | undefined - >(); - const queryClient = useQueryClient(); - const { enqueueSnackbar } = useSnackbar(); - - useEffect(() => { - if (!entityIRI || !typeIRI) return; - const _whereEntity = ` <${entityIRI}> a <${typeIRI}> . `; - setWhereEntity(_whereEntity); - return () => { - resolveSourceIRIs(entityIRI); - }; - }, [entityIRI, typeIRI, setWhereEntity, resolveSourceIRIs]); - - const getClassIRIs = useCallback( - async (entityIRI_: string) => { - const ownIRI = entityIRI_ || entityIRI; - if (!ownIRI || !selectFetch) return null; - const classes = df.variable("classes"); - const query = SELECT`${classes}`.WHERE` - <${ownIRI}> a ${classes} . - `.build(queryBuildOptions); - try { - const result = await selectFetch(query); - return result.map(({ classes }) => classes.value); - } catch (e) { - console.error(e); - } - return null; - }, - [entityIRI, selectFetch, queryBuildOptions], - ); - - const exists = useCallback(async () => { - if (!whereEntity) return false; - const query = ASK`${whereEntity}`.build(queryBuildOptions); - try { - return await askFetch(query); - } catch (e) { - console.error(e); - } - return false; - }, [whereEntity, askFetch, queryBuildOptions]); - - const load = useCallback(async () => { - if (!entityIRI || !whereEntity) return; - const { construct, whereRequired, whereOptionals } = jsonSchema2construct( - entityIRI, - schema, - [], - ["@id", "@type"], - ); - let query = CONSTRUCT`${construct}`.WHERE` - ${whereEntity} - ${whereRequired} - ${whereOptionals} - `.build(queryBuildOptions); - query = `PREFIX : <${defaultPrefix}> ` + query; - try { - const ds = await constructFetch(query); - const subjects: Set = new Set(); - // @ts-ignore - for (const quad of ds) { - if (quad.subject.termType === "NamedNode") { - subjects.add(quad.subject.value); - } - } - updateSourceToTargets(entityIRI, Array.from(subjects)); - const resultJSON = jsonSchemaGraphInfuser( - defaultPrefix, - entityIRI, - ds as Dataset, - schema, - walkerOptions, - ); - setIsUpdate(true); - //setData(resultJSON) - onLoad && onLoad(resultJSON); - return resultJSON; - } catch (e) { - console.error(e); - } - }, [ - entityIRI, - whereEntity, - setIsUpdate, - defaultPrefix, - constructFetch, - updateSourceToTargets, - onLoad, - schema, - queryBuildOptions, - walkerOptions, - ]); - - const remove = useCallback(async () => { - if (!entityIRI || !whereEntity) return; - const { construct, whereRequired, whereOptionals } = jsonSchema2construct( - entityIRI, - schema, - ["@id"], - ["@id", "@type"], - ); - let query = DELETE` ${construct} ` - .WHERE`${whereEntity} ${whereRequired}\n${whereOptionals}`.build( - queryBuildOptions, - ); - query = `PREFIX : <${defaultPrefix}> ` + query; - await updateFetch(query); - enqueueSnackbar("Daten wurden entfernt", { variant: "info" }); - }, [ - entityIRI, - whereEntity, - defaultPrefix, - updateFetch, - enqueueSnackbar, - queryBuildOptions, - schema, - ]); - - //TODO: this code is a mess, refactor it (it has matured historically) - const save = useCallback( - async (data_?: any) => { - let dataToBeSaved = data_; - const finalEntityIRI = dataToBeSaved?.["@id"] || entityIRI; - const finalTypeIRI = dataToBeSaved?.["@type"] || typeIRI; - if (!dataToBeSaved) { - if (!data || !entityIRI) return; - dataToBeSaved = { - ...data, - "@type": typeIRI, - "@id": entityIRI, - }; - } - const finalWhereEntity = ` <${finalEntityIRI}> a <${finalTypeIRI}> . `; - const ntWriter = new N3.Writer({ format: "Turtle" }); - const ds = await jsonld.toRDF(dataToBeSaved); - - // @ts-ignore - const ntriples = ntWriter.quadsToString([...ds]).replaceAll("_:_:", "_:"); - if (!isUpdate && !upsertByDefault) { - const updateQuery = INSERT.DATA` ${ntriples} `; - const query = updateQuery.build(); - await updateFetch(query); - setIsUpdate(true); - } else { - const { construct, whereRequired, whereOptionals } = - jsonSchema2construct( - finalEntityIRI, - schema, - ["@id"], - ["@id", "@type"], - ); - const queries = [ - DELETE` ${construct} ` - .WHERE`${finalWhereEntity} ${whereRequired}\n${whereOptionals}`.build( - queryBuildOptions, - ), - INSERT.DATA` ${ntriples} `.build(queryBuildOptions), - ]; - for (let query of queries) { - query = `PREFIX : <${defaultPrefix}> ` + query; - await updateFetch(query); - } - // temporary add message here - enqueueSnackbar("Daten wurden gespeichert", { variant: "success" }); - for (const sourceIRI of resolveSourceIRIs(finalEntityIRI)) { - await queryClient.invalidateQueries(["load", sourceIRI]); - } - } - }, - [ - entityIRI, - typeIRI, - data, - isUpdate, - setIsUpdate, - defaultPrefix, - updateFetch, - upsertByDefault, - queryClient, - enqueueSnackbar, - resolveSourceIRIs, - schema, - queryBuildOptions, - ], - ); - - const reset = useCallback(() => { - setData && setData({}, false); - setLastEntityLoaded(undefined); - load(); - enqueueSnackbar("Daten wurden zurückgesetzt", { variant: "info" }); - }, [setData, setLastEntityLoaded, load, enqueueSnackbar]); - const handleLoadSuccess = useCallback( - (data: any) => { - if (data) { - setData && setData(data, entityIRI === lastEntityLoaded); - setLastEntityLoaded(entityIRI); - } - }, - [entityIRI, setLastEntityLoaded, lastEntityLoaded, setData], - ); - - const { enabled, ...queryOptionsRest } = queryOptions || {}; - const queryResults = useQuery( - ["oldLoad", entityIRI], - async () => { - const res = await load(); - return res || null; - }, - { - onSuccess: handleLoadSuccess, - enabled: Boolean(entityIRI && whereEntity) && enabled, - refetchOnWindowFocus: false, - ...queryOptionsRest, - }, - ); - const { refetch, isLoading } = queryResults; - - return { - ...queryResults, - exists, - load: refetch, - save, - remove, - isUpdate, - getClassIRIs, - setIsUpdate, - reset, - // @ts-ignore - ready: Boolean(askFetch && constructFetch && updateFetch), - }; -}; diff --git a/apps/exhibition-live/components/state/useThemeSettings.ts b/apps/exhibition-live/components/state/useThemeSettings.ts index 866ffdc7..7923eab3 100644 --- a/apps/exhibition-live/components/state/useThemeSettings.ts +++ b/apps/exhibition-live/components/state/useThemeSettings.ts @@ -1,8 +1,12 @@ import { create } from "zustand"; +import { NextFontWithVariable } from "next/dist/compiled/@next/font"; + +// Custom fonts bundled (i.e. no external requests), see type UseThemeSettings = { isOpen: string[]; fontFamily: string; + font?: NextFontWithVariable; borderRadius: number; opened: boolean; defaultId: string; @@ -12,7 +16,7 @@ type UseThemeSettings = { export const useThemeSettings = create((set, get) => ({ isOpen: [], // for active default menu defaultId: "default", - fontFamily: "'Roboto', sans-serif", + fontFamily: "sans-serif", borderRadius: 12, opened: true, navType: "light", diff --git a/apps/exhibition-live/components/state/useTypeIRIFromEntity.ts b/apps/exhibition-live/components/state/useTypeIRIFromEntity.ts deleted file mode 100644 index f0557352..00000000 --- a/apps/exhibition-live/components/state/useTypeIRIFromEntity.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { useQuery } from "@tanstack/react-query"; -import { getClasses } from "../utils/crud"; -import { useGlobalCRUDOptions } from "./useGlobalCRUDOptions"; -import { defaultPrefix, defaultQueryBuilderOptions } from "../form/formConfigs"; - -export const useTypeIRIFromEntity = (entityIRI: string) => { - const { crudOptions } = useGlobalCRUDOptions(); - const selectFetch = crudOptions?.selectFetch; - const { data: typeIRIs } = useQuery( - ["classes", entityIRI], - async () => { - return await getClasses(entityIRI, selectFetch, { - queryBuildOptions: defaultQueryBuilderOptions, - defaultPrefix: defaultPrefix, - }); - }, - { - enabled: Boolean(entityIRI && selectFetch), - }, - ); - return typeIRIs; -}; diff --git a/apps/exhibition-live/components/theme/icons/TabIcon.tsx b/apps/exhibition-live/components/theme/icons/TabIcon.tsx deleted file mode 100644 index d0d51b81..00000000 --- a/apps/exhibition-live/components/theme/icons/TabIcon.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import React from "react"; -import { SvgIcon } from "@mui/material"; - -const TabIconSvgComponent = (props) => ( - - - -); - -export const TabIcon = () => ( - - - -); diff --git a/apps/exhibition-live/components/theme/icons/index.ts b/apps/exhibition-live/components/theme/icons/index.ts deleted file mode 100644 index 4d2cca8b..00000000 --- a/apps/exhibition-live/components/theme/icons/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./TabIcon"; diff --git a/apps/exhibition-live/components/types/graphql.ts b/apps/exhibition-live/components/types/graphql.ts deleted file mode 100644 index 5ba663e6..00000000 --- a/apps/exhibition-live/components/types/graphql.ts +++ /dev/null @@ -1,645 +0,0 @@ -import { useQuery, UseQueryOptions } from "@tanstack/react-query"; - -import { useFetchData } from "../graphql/useFetchData"; - -export type Maybe = T | null; -export type InputMaybe = Maybe; -export type Exact = { - [K in keyof T]: T[K]; -}; -export type MakeOptional = Omit & { - [SubKey in K]?: Maybe; -}; -export type MakeMaybe = Omit & { - [SubKey in K]: Maybe; -}; -/** All built-in and custom scalars, mapped to their actual values */ -export type Scalars = { - ID: string; - String: string; - Boolean: boolean; - Int: number; - Float: number; - Date: any; - DateTime: any; - GlobalID: any; - JSON: any; - UUID: any; -}; - -export type CorporationType = { - __typename?: "CorporationType"; - description?: Maybe; - id: Scalars["GlobalID"]; - imported?: Maybe; - name: Scalars["String"]; - nameVariants?: Maybe; - parent: CorporationType; -}; - -export type CreateImportPayload = DataImportType | OperationInfo; - -export type CreatePersonPayload = OperationInfo | PersonType; - -export type DataImportFilter = { - status?: InputMaybe; - uuid?: InputMaybe; -}; - -export type DataImportInput = { - importTime?: InputMaybe; - remarks?: InputMaybe; - status?: InputMaybe; - uuid: Scalars["UUID"]; -}; - -export type DataImportPartialInput = { - id: Scalars["GlobalID"]; -}; - -export type DataImportType = { - __typename?: "DataImportType"; - importTime: Scalars["DateTime"]; - remarks: Scalars["String"]; - status: Scalars["String"]; - uuid: Scalars["UUID"]; -}; - -export type DataSourceType = { - __typename?: "DataSourceType"; - description?: Maybe; - id: Scalars["GlobalID"]; - title: Scalars["String"]; -}; - -export type DeleteImportPayload = DataImportType | OperationInfo; - -export type DeletePersonPayload = OperationInfo | PersonType; - -export type EventTypeType = { - __typename?: "EventTypeType"; - description?: Maybe; - id: Scalars["GlobalID"]; - imported?: Maybe; - tags?: Maybe>; - title: Scalars["String"]; -}; - -export type ExhibitionCategoryType = { - __typename?: "ExhibitionCategoryType"; - description?: Maybe; - name: Scalars["String"]; -}; - -export type ExhibitionFilter = { - fromDate?: InputMaybe; - id?: InputMaybe; - search?: InputMaybe; - title?: InputMaybe; - toDate?: InputMaybe; -}; - -export type ExhibitionObjectPersonType = { - __typename?: "ExhibitionObjectPersonType"; - exhibitionObject: ExhibitionObjectType; - id: Scalars["GlobalID"]; - person: PersonType; - role: RoleType; -}; - -export type ExhibitionObjectType = { - __typename?: "ExhibitionObjectType"; - dating?: Maybe; - description?: Maybe; - id: Scalars["GlobalID"]; - involvedPersons?: Maybe>; - resources?: Maybe>; - title: Scalars["String"]; -}; - -export type ExhibitionSeriesType = { - __typename?: "ExhibitionSeriesType"; - description?: Maybe; - fromDate?: Maybe; - fromType?: Maybe; - id: Scalars["GlobalID"]; - openingDate?: Maybe; - parent?: Maybe; - seriesType?: Maybe; - tags?: Maybe>; - title: Scalars["String"]; - toDate?: Maybe; - toType?: Maybe; -}; - -export type ExhibitionType = { - __typename?: "ExhibitionType"; - description?: Maybe; - exhibitionCategory?: Maybe; - exhibitionObjects?: Maybe>; - exhibitionSeries?: Maybe; - exhibitionType: EventTypeType; - externalId?: Maybe; - fromDate?: Maybe; - fromDateDisplay?: Maybe; - fromType?: Maybe; - id: Scalars["GlobalID"]; - imported?: Maybe; - involvedCorporations: Array; - involvedPersons: Array; - locations?: Maybe>; - originalTitle?: Maybe; - otherDates: Array; - places?: Maybe>; - published: Scalars["Boolean"]; - resources?: Maybe>; - source?: Maybe; - subtitle?: Maybe; - tags?: Maybe>; - title: Scalars["String"]; - toDate?: Maybe; - toDateDisplay?: Maybe; - toType?: Maybe; - weblink?: Maybe; -}; - -export type GlobalIdFilterLookup = { - contains?: InputMaybe; - endsWith?: InputMaybe; - exact?: InputMaybe; - gt?: InputMaybe; - gte?: InputMaybe; - iContains?: InputMaybe; - iEndsWith?: InputMaybe; - iExact?: InputMaybe; - iRegex?: InputMaybe; - iStartsWith?: InputMaybe; - inList?: InputMaybe>; - isNull?: InputMaybe; - lt?: InputMaybe; - lte?: InputMaybe; - range?: InputMaybe>; - regex?: InputMaybe; - startsWith?: InputMaybe; -}; - -export type IntFilterLookup = { - contains?: InputMaybe; - endsWith?: InputMaybe; - exact?: InputMaybe; - gt?: InputMaybe; - gte?: InputMaybe; - iContains?: InputMaybe; - iEndsWith?: InputMaybe; - iExact?: InputMaybe; - iRegex?: InputMaybe; - iStartsWith?: InputMaybe; - inList?: InputMaybe>; - isNull?: InputMaybe; - lt?: InputMaybe; - lte?: InputMaybe; - range?: InputMaybe>; - regex?: InputMaybe; - startsWith?: InputMaybe; -}; - -export type InvolvedCorporationType = { - __typename?: "InvolvedCorporationType"; - corporation: CorporationType; - exhibition: ExhibitionType; - id: Scalars["GlobalID"]; - role: RoleType; -}; - -export type InvolvedPersonType = { - __typename?: "InvolvedPersonType"; - exhibition: ExhibitionType; - id: Scalars["GlobalID"]; - person: PersonType; - role: RoleType; -}; - -export type LocationType = { - __typename?: "LocationType"; - description?: Maybe; - geodata?: Maybe; - id: Scalars["GlobalID"]; - parent?: Maybe; - title: Scalars["String"]; - titleVariants?: Maybe; -}; - -export type Mutation = { - __typename?: "Mutation"; - createImport: CreateImportPayload; - createPerson: CreatePersonPayload; - deleteImport: DeleteImportPayload; - deletePerson: DeletePersonPayload; - updateImport: UpdateImportPayload; - updatePerson: UpdatePersonPayload; -}; - -export type MutationCreateImportArgs = { - input: DataImportInput; -}; - -export type MutationCreatePersonArgs = { - input: PersonInput; -}; - -export type MutationDeleteImportArgs = { - input: NodeInput; -}; - -export type MutationDeletePersonArgs = { - input: NodeInput; -}; - -export type MutationUpdateImportArgs = { - input: DataImportPartialInput; -}; - -export type MutationUpdatePersonArgs = { - input: PersonPartialInput; -}; - -/** Input of an object that implements the `Node` interface. */ -export type NodeInput = { - id: Scalars["GlobalID"]; -}; - -/** Multiple messages returned by an operation. */ -export type OperationInfo = { - __typename?: "OperationInfo"; - /** List of messages returned by the operation. */ - messages: Array; -}; - -/** An error that happened while executing an operation. */ -export type OperationMessage = { - __typename?: "OperationMessage"; - /** The field that caused the error, or `null` if it isn't associated with any particular field. */ - field?: Maybe; - /** The kind of this message. */ - kind: OperationMessageKind; - /** The error message. */ - message: Scalars["String"]; -}; - -/** The kind of the returned message. */ -export enum OperationMessageKind { - Error = "ERROR", - Info = "INFO", - Permission = "PERMISSION", - Validation = "VALIDATION", - Warning = "WARNING", -} - -export type OtherDateType = { - __typename?: "OtherDateType"; - dateType: Scalars["Int"]; - dateValue: Scalars["Date"]; - exhibition: ExhibitionType; - id: Scalars["GlobalID"]; -}; - -export type PersonFilter = { - id?: InputMaybe; - name?: InputMaybe; - nameVariants?: InputMaybe; - search?: InputMaybe; -}; - -export type PersonInput = { - cimport?: InputMaybe; - description?: InputMaybe; - externalId?: InputMaybe; - gender?: InputMaybe; - name: Scalars["String"]; - nameVariants?: InputMaybe; - uimport?: InputMaybe; -}; - -export type PersonPartialInput = { - id: Scalars["GlobalID"]; -}; - -export type PersonType = { - __typename?: "PersonType"; - description?: Maybe; - externalId?: Maybe; - gender?: Maybe; - id: Scalars["GlobalID"]; - importedBy?: Maybe; - lastNormUpdate?: Maybe; - memberOfCorp?: Maybe>; - name: Scalars["String"]; - nameVariants?: Maybe; - normdata?: Maybe; -}; - -export type PersonTypeImportedByArgs = { - pk: Scalars["ID"]; -}; - -export type PlaceType = { - __typename?: "PlaceType"; - description?: Maybe; - geodata?: Maybe; - id: Scalars["GlobalID"]; - imported?: Maybe; - location?: Maybe; - parent?: Maybe; - title: Scalars["String"]; - titleVariants?: Maybe; -}; - -export type Query = { - __typename?: "Query"; - getDataimport: DataImportType; - getDataimports: Array; - getExhibition: ExhibitionType; - getExhibitions: Array; - getPerson: PersonType; - getPersons: Array; -}; - -export type QueryGetDataimportArgs = { - pk: Scalars["ID"]; -}; - -export type QueryGetDataimportsArgs = { - filters?: InputMaybe; -}; - -export type QueryGetExhibitionArgs = { - pk: Scalars["ID"]; -}; - -export type QueryGetExhibitionsArgs = { - filters?: InputMaybe; -}; - -export type QueryGetPersonArgs = { - pk: Scalars["ID"]; -}; - -export type QueryGetPersonsArgs = { - filters?: InputMaybe; -}; - -export type ResourceType = { - __typename?: "ResourceType"; - corporation: CorporationType; - description?: Maybe; - id: Scalars["GlobalID"]; - imported?: Maybe; - person: PersonType; - ressourceType: RessourceTypeType; - signature?: Maybe; - title: Scalars["String"]; - url?: Maybe; -}; - -export type RessourceTypeType = { - __typename?: "RessourceTypeType"; - description?: Maybe; - id: Scalars["GlobalID"]; - title: Scalars["String"]; -}; - -export type RoleType = { - __typename?: "RoleType"; - description?: Maybe; - id: Scalars["GlobalID"]; - roleType: Scalars["Int"]; - title: Scalars["String"]; -}; - -export type SeriesTypeType = { - __typename?: "SeriesTypeType"; - description?: Maybe; - id: Scalars["GlobalID"]; - title: Scalars["String"]; -}; - -export type StrFilterLookup = { - contains?: InputMaybe; - endsWith?: InputMaybe; - exact?: InputMaybe; - gt?: InputMaybe; - gte?: InputMaybe; - iContains?: InputMaybe; - iEndsWith?: InputMaybe; - iExact?: InputMaybe; - iRegex?: InputMaybe; - iStartsWith?: InputMaybe; - inList?: InputMaybe>; - isNull?: InputMaybe; - lt?: InputMaybe; - lte?: InputMaybe; - range?: InputMaybe>; - regex?: InputMaybe; - startsWith?: InputMaybe; -}; - -export type TagType = { - __typename?: "TagType"; - description?: Maybe; - id: Scalars["GlobalID"]; - parent: TagType; - title: Scalars["String"]; -}; - -export type UuidFilterLookup = { - contains?: InputMaybe; - endsWith?: InputMaybe; - exact?: InputMaybe; - gt?: InputMaybe; - gte?: InputMaybe; - iContains?: InputMaybe; - iEndsWith?: InputMaybe; - iExact?: InputMaybe; - iRegex?: InputMaybe; - iStartsWith?: InputMaybe; - inList?: InputMaybe>; - isNull?: InputMaybe; - lt?: InputMaybe; - lte?: InputMaybe; - range?: InputMaybe>; - regex?: InputMaybe; - startsWith?: InputMaybe; -}; - -export type UpdateImportPayload = DataImportType | OperationInfo; - -export type UpdatePersonPayload = OperationInfo | PersonType; - -export type AllExhibitionsQueryVariables = Exact<{ [key: string]: never }>; - -export type AllExhibitionsQuery = { - __typename?: "Query"; - getExhibitions: Array<{ - __typename?: "ExhibitionType"; - id: any; - title: string; - description?: string | null; - fromDate?: number | null; - toDate?: number | null; - weblink?: string | null; - places?: Array<{ - __typename?: "PlaceType"; - title: string; - location?: { __typename?: "LocationType"; id: any; title: string } | null; - }> | null; - locations?: Array<{ - __typename?: "LocationType"; - id: any; - title: string; - }> | null; - }>; -}; - -export type SearchExhibitionsQueryVariables = Exact<{ - searchString?: InputMaybe; -}>; - -export type SearchExhibitionsQuery = { - __typename?: "Query"; - getExhibitions: Array<{ - __typename?: "ExhibitionType"; - id: any; - title: string; - description?: string | null; - fromDate?: number | null; - toDate?: number | null; - weblink?: string | null; - places?: Array<{ - __typename?: "PlaceType"; - title: string; - location?: { __typename?: "LocationType"; id: any; title: string } | null; - }> | null; - locations?: Array<{ - __typename?: "LocationType"; - id: any; - title: string; - }> | null; - }>; -}; - -export type AllPersonsQueryVariables = Exact<{ [key: string]: never }>; - -export type AllPersonsQuery = { - __typename?: "Query"; - getPersons: Array<{ - __typename?: "PersonType"; - id: any; - nameVariants?: string | null; - name: string; - description?: string | null; - gender?: string | null; - normdata?: any | null; - }>; -}; - -export const AllExhibitionsDocument = ` - query allExhibitions { - getExhibitions { - id - title - description - fromDate - toDate - places { - title - location { - id - title - } - } - locations { - id - title - } - weblink - } -} - `; -export const useAllExhibitionsQuery = < - TData = AllExhibitionsQuery, - TError = unknown, ->( - variables?: AllExhibitionsQueryVariables, - options?: UseQueryOptions, -) => - useQuery( - variables === undefined - ? ["allExhibitions"] - : ["allExhibitions", variables], - useFetchData( - AllExhibitionsDocument, - ).bind(null, variables), - options, - ); -export const SearchExhibitionsDocument = ` - query searchExhibitions($searchString: String) { - getExhibitions(filters: {title: {iContains: $searchString}}) { - id - title - description - fromDate - toDate - places { - title - location { - id - title - } - } - locations { - id - title - } - weblink - } -} - `; -export const useSearchExhibitionsQuery = < - TData = SearchExhibitionsQuery, - TError = unknown, ->( - variables?: SearchExhibitionsQueryVariables, - options?: UseQueryOptions, -) => - useQuery( - variables === undefined - ? ["searchExhibitions"] - : ["searchExhibitions", variables], - useFetchData( - SearchExhibitionsDocument, - ).bind(null, variables), - options, - ); -export const AllPersonsDocument = ` - query allPersons { - getPersons { - id - nameVariants - name - description - gender - normdata - } -} - `; -export const useAllPersonsQuery = ( - variables?: AllPersonsQueryVariables, - options?: UseQueryOptions, -) => - useQuery( - variables === undefined ? ["allPersons"] : ["allPersons", variables], - useFetchData( - AllPersonsDocument, - ).bind(null, variables), - options, - ); diff --git a/apps/exhibition-live/components/types/settings.ts b/apps/exhibition-live/components/types/settings.ts new file mode 100644 index 00000000..57b48323 --- /dev/null +++ b/apps/exhibition-live/components/types/settings.ts @@ -0,0 +1,55 @@ +export type SparqlEndpoint = { + label?: string; + endpoint: string; + active: boolean; + auth?: { + username?: string; + password?: string; + token?: string; + }; + provider?: + | "allegro" + | "oxigraph" + | "worker" + | "blazegraph" + | "virtuoso" + | "qlever" + | "rest"; +}; +export type Features = { + enablePreview?: boolean; + enableDebug?: boolean; + enableBackdrop?: boolean; + enableStylizedCard?: boolean; +}; +export type OpenAIConfig = { + organization?: string; + apiKey?: string; +}; +export type GoogleDriveConfig = { + apiKey?: string; +}; +export type ExternalAuthorityConfig = { + kxp?: { + endpoint?: string; + baseURL?: string; + recordSchema?: string; + }; +}; +export type Settings = { + lockedEndpoint: boolean; + sparqlEndpoints: SparqlEndpoint[]; + + features: Features; + openai: OpenAIConfig; + googleDrive: GoogleDriveConfig; + externalAuthority: ExternalAuthorityConfig; +}; +export type UseLocalSettings = { + settingsOpen: boolean; + sparqlEndpoints: SparqlEndpoint[]; + setSparqlEndpoints: (endpoints: SparqlEndpoint[]) => void; + openSettings: () => void; + closeSettings: () => void; + getActiveEndpoint: () => SparqlEndpoint | undefined; +}; diff --git a/apps/exhibition-live/components/utils/ai/index.ts b/apps/exhibition-live/components/utils/ai/index.ts deleted file mode 100644 index 8a7b042a..00000000 --- a/apps/exhibition-live/components/utils/ai/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./mapUsingAI"; diff --git a/apps/exhibition-live/components/utils/ai/mapUsingAI.ts b/apps/exhibition-live/components/utils/ai/mapUsingAI.ts deleted file mode 100644 index 90d66fba..00000000 --- a/apps/exhibition-live/components/utils/ai/mapUsingAI.ts +++ /dev/null @@ -1,172 +0,0 @@ -import { ChatCompletionRequestMessage, Configuration, OpenAIApi } from "openai"; -import { JSONSchema7 } from "json-schema"; -import { filterForPrimitivePropertiesAndArrays } from "@slub/json-schema-utils"; - -type Context = { - jsonSchema: JSONSchema7; - openai?: { - model?: string; - organization?: string; - apiKey?: string; - }; -}; - -const defaultModel = "gpt-3.5-turbo"; -export const mapAbstractDataUsingAI = async ( - id: string, - typeName: string, - data: any, - context: Context, -): Promise => { - const { jsonSchema, openai } = context; - if (!openai?.organization || !openai?.apiKey) { - console.warn("No OpenAI API Key or Organization set"); - return null; - } - const configuration = new Configuration(openai); - const openaiInstance = new OpenAIApi(configuration); - const entrySchema = { - type: "object", - properties: filterForPrimitivePropertiesAndArrays(jsonSchema.properties), - }; - try { - const firstMessages: ChatCompletionRequestMessage[] = [ - { - role: "system", - content: - "The task is to map an abstract and description of an entity from a librarian catalogue to a more simple model of a user given JSON Schema. First listen to the next two user prompts, only respond to system commands.", - }, - { - role: "user", - content: `The JSONSchema of the object of type \`${typeName}\` is: - \`\`\`json - ${JSON.stringify(entrySchema)} - \`\`\``, - }, - { - role: "user", - content: `The data returned from the library catalog is: - \`\`\`json - ${JSON.stringify(data)} - \`\`\``, - }, - { - role: "system", - content: `Extract dates, like beginning and end of the ${typeName} from the text according to the schema. Hint: dates tha map to an integer should be converted to YYYYMMDD, if any of the part is unknown fill it with 0. Omit null values in the resultset.`, - }, - ]; - const response = await openaiInstance.createChatCompletion({ - model: openai?.model || defaultModel, - messages: firstMessages, - max_tokens: 1500, - }); - const dataFromGNDRaw = - response.data?.choices?.[0]?.message?.content || "{}"; - console.log({ data: response.data, dataFromGNDRaw }); - const { ["@id"]: _1, ...dataFromGND } = JSON.parse(dataFromGNDRaw); - const inject = { - idAuthority: { - "@id": id, - }, - lastNormUpdate: new Date().toISOString(), - }; - return { ...dataFromGND, ...inject }; - } catch (e) { - console.error("could not guess mapping", e); - } - return null; -}; - -export const mapDataUsingAI = async ( - id: string, - typeName: string, - data: any, - context: Context, -): Promise => { - const { jsonSchema, openai } = context; - if (!open || !openai?.organization || !openai?.apiKey) { - console.log("No OpenAI API Key or Organization set"); - return null; - } - const { model } = openai; - const configuration = new Configuration(openai); - const openaiInstance = new OpenAIApi(configuration); - const entrySchema = { - type: "object", - properties: filterForPrimitivePropertiesAndArrays(jsonSchema.properties), - }; - try { - const firstMessages: ChatCompletionRequestMessage[] = [ - { - role: "system", - content: - "The task is to map complex norm data from the GND to a more simple model of a user given JSON Schema. First listen to the next two user prompts, only respond to system commands.", - }, - { - role: "user", - content: `The JSONSchema of the object of type \`${typeName}\` is: - \`\`\`json - ${JSON.stringify(entrySchema)} - \`\`\``, - }, - { - role: "user", - content: `The data returned from the GND is: - \`\`\`json - ${JSON.stringify(data)} - \`\`\``, - }, - { - role: "system", - content: - "Output the result of mapping the GND data to the schema (minified JSON without newlines). Hint: dates tha map to an integer should be converted to YYYYMMDD, if any of the part is unknown fill it with 0. Omit null values in the resultset.", - }, - ]; - const response = await openaiInstance.createChatCompletion({ - model: model, - messages: firstMessages, - max_tokens: 1200, - }); - const dataFromGNDRaw = - response.data?.choices?.[0]?.message?.content || "{}"; - console.log({ data: response.data, dataFromGNDRaw }); - const { ["@id"]: _1, ...dataFromGND } = JSON.parse(dataFromGNDRaw); - const inject = { - idAuthority: { - "@id": id, - }, - lastNormUpdate: new Date().toISOString(), - }; - const newData = { ...dataFromGND, ...inject }; - return newData; - - /* - const generateMappingMessage: ChatCompletionRequestMessage[] = [ - { - role: "system", - content: - "for each mapped target field, give a small declarative representation of gnd fields used as input and a strategy used for mapping. The different strategies will be implemented by a developer. Output the declarations as JSON.", - }, - ]; - const mappingResponse = await openaiInstance.createChatCompletion({ - model: model, - messages: [ - ...firstMessages, - { - role: "assistant", - content: dataFromGNDRaw, - }, - ...generateMappingMessage, - ], - max_tokens: 1200, - }); - const mappingDataRaw = - mappingResponse.data?.choices?.[0]?.message?.content || "{}"; - console.log({ mappingDataRaw }); - - */ - } catch (e) { - console.error("could not guess mapping", e); - } - return null; -}; diff --git a/apps/exhibition-live/components/utils/core/index.ts b/apps/exhibition-live/components/utils/core/index.ts deleted file mode 100644 index 43633253..00000000 --- a/apps/exhibition-live/components/utils/core/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "@slub/edb-core-utils"; diff --git a/apps/exhibition-live/components/utils/crud/index.ts b/apps/exhibition-live/components/utils/crud/index.ts deleted file mode 100644 index e90ff6bb..00000000 --- a/apps/exhibition-live/components/utils/crud/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "@slub/sparql-schema"; -export * from "./basicFieldsQuery"; -export * from "./loadEntityBasics"; diff --git a/apps/exhibition-live/components/utils/dev/YasguiSPARQLEditor.tsx b/apps/exhibition-live/components/utils/dev/YasguiSPARQLEditor.tsx deleted file mode 100644 index ab8d350a..00000000 --- a/apps/exhibition-live/components/utils/dev/YasguiSPARQLEditor.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import "@triply/yasgui/build/yasgui.min.css"; - -import Yasgui from "@triply/yasgui"; -import React, { FunctionComponent, useEffect, useState } from "react"; - -import { exhibitionPrefixes } from "../../exhibtion"; - -interface OwnProps { - onInit?: (yasgu: Yasgui) => void; -} - -type Props = OwnProps; - -const withPrefixes = (yg: Yasgui) => { - const yasqe = yg.getTab(yg.persistentConfig.currentId())?.getYasqe(); - const yasqr = yg.getTab(yg.persistentConfig.currentId())?.getYasr(); - yasqe?.addPrefixes(exhibitionPrefixes); - //yasqr?.set - return yg; -}; - -const YasguiSPARQLEditor: FunctionComponent = ({ onInit }) => { - const [yasgui, setYasgui] = useState(null); - - useEffect(() => { - setYasgui((yg) => { - const el = document.getElementById("yasgui"); - return !el || yg - ? yg - : withPrefixes( - new Yasgui(el, { - yasqe: { - queryingDisabled: undefined, - showQueryButton: true, - }, - }), - ); - }); - }, [setYasgui]); - useEffect(() => { - if (yasgui && onInit) onInit(yasgui); - }, [onInit, yasgui]); - - return
; -}; - -export default YasguiSPARQLEditor; diff --git a/apps/exhibition-live/components/utils/discover/findEntityByAuthorityIRI.ts b/apps/exhibition-live/components/utils/discover/findEntityByAuthorityIRI.ts deleted file mode 100644 index f911e621..00000000 --- a/apps/exhibition-live/components/utils/discover/findEntityByAuthorityIRI.ts +++ /dev/null @@ -1,38 +0,0 @@ -import df from "@rdfjs/data-model"; -import { SELECT } from "@tpluscode/sparql-builder"; -import { - defaultPrefix, - defaultQueryBuilderOptions, -} from "../../form/formConfigs"; - -export const findEntityByAuthorityIRI = async ( - authorityIRI: string, - typeIRI: string | undefined, - doQuery: (query: string) => Promise, - limit: number = 10, -) => { - const subjectV = df.variable("subject"); - let query = ( - typeIRI - ? SELECT.DISTINCT` ${subjectV}`.WHERE` - ${subjectV} :idAuthority <${authorityIRI}> . - ${subjectV} a <${typeIRI}> . - ` - : SELECT.DISTINCT` ${subjectV}`.WHERE` - ${subjectV} :idAuthority <${authorityIRI}> . - ` - ) - .LIMIT(limit) - .build(defaultQueryBuilderOptions); - - query = `PREFIX : <${defaultPrefix}> - ${query}`; - - try { - const bindings = await doQuery(query); - return bindings.map((binding: any) => binding.subject.value); - } catch (e) { - console.error("Error finding entity by authority IRI", e); - return []; - } -}; diff --git a/apps/exhibition-live/components/utils/discover/findEntityByClass.ts b/apps/exhibition-live/components/utils/discover/findEntityByClass.ts deleted file mode 100644 index c2f9779a..00000000 --- a/apps/exhibition-live/components/utils/discover/findEntityByClass.ts +++ /dev/null @@ -1,96 +0,0 @@ -import df from "@rdfjs/data-model"; -import { SELECT } from "@tpluscode/sparql-builder"; - -import { - defaultPrefix, - defaultQueryBuilderOptions, -} from "../../form/formConfigs"; - -export function fixSparqlOrder(sparqlQuery) { - const regex = /(ORDER BY\s+[^ ]+)(\s*)GROUP BY\s+\(([^\)]+)\)/gm; - return sparqlQuery.replace(regex, "GROUP BY $3 $2\n$1"); -} -export const findEntityByClass: ( - searchString: string | null, - typeIRI: string, - doQuery: (query: string) => Promise, - limit?: number, -) => Promise = async ( - searchString: string | null, - typeIRI: string, - doQuery: (query: string) => Promise, - limit: number = 10, -) => { - const subjectV = df.variable("subject"), - nameV = df.variable("name"), - titleV = df.variable("title"), - allDescriptionV = df.variable("allDescription"), - descriptionV = df.variable("description"), - concatenatedV = df.variable("concatenated"), - safeNameV = df.variable("safeName"), - safeTitleV = df.variable("safeTitle"), - safeDescriptionV = df.variable("safeDescription"), - oneOfTitleV = df.variable("oneOfTitle"), - firstOneOfTitleV = df.variable("firstOneOfTitle"), - allImagesV = df.variable("allImages"), - imageV = df.variable("image"); - - let query = - searchString && searchString.length > 0 - ? SELECT.DISTINCT` ${subjectV} (SAMPLE(${oneOfTitleV}) AS ${firstOneOfTitleV}) (SAMPLE(${allImagesV}) AS ${imageV}) (SAMPLE(${allDescriptionV}) AS ${descriptionV})` - .WHERE` - ${subjectV} a <${typeIRI}> . - OPTIONAL {${subjectV} :name ${nameV} .} - OPTIONAL {${subjectV} :title ${titleV} .} - OPTIONAL {${subjectV} :description ${allDescriptionV} .} - OPTIONAL {${subjectV} :image ${allImagesV} .} - - BIND (COALESCE(${nameV}, "") AS ${safeNameV}) - BIND (COALESCE(${titleV}, "") AS ${safeTitleV}) - BIND (COALESCE(${descriptionV}, "") AS ${safeDescriptionV}) - - BIND (CONCAT(${safeNameV}, " ", ${safeTitleV}, " ", ${safeDescriptionV}) AS ${concatenatedV}) - BIND (COALESCE(${nameV}, ${titleV}, ${descriptionV}, "") AS ${oneOfTitleV}) - FILTER(contains(lcase(${concatenatedV}), lcase("${searchString}") )) . - FILTER isIRI(${subjectV}) - FILTER (strlen(${oneOfTitleV}) > 0) - ` - .LIMIT(limit) - .GROUP() - .BY(subjectV) - .ORDER() - .BY(firstOneOfTitleV) - .build(defaultQueryBuilderOptions) - : SELECT.DISTINCT` ${subjectV} (SAMPLE(${oneOfTitleV}) AS ${firstOneOfTitleV}) (SAMPLE(${allImagesV}) AS ${imageV}) (SAMPLE(${allDescriptionV}) AS ${descriptionV})` - .WHERE` - ${subjectV} a <${typeIRI}> . - OPTIONAL {${subjectV} :name ${nameV} .} - OPTIONAL {${subjectV} :title ${titleV} .} - OPTIONAL {${subjectV} :description ${allDescriptionV} .} - OPTIONAL {${subjectV} :image ${allImagesV} .} - BIND (COALESCE(${nameV}, ${titleV}, ${descriptionV}, "") AS ${oneOfTitleV}) - FILTER isIRI(${subjectV}) - FILTER (strlen(${oneOfTitleV}) > 0) - ` - .LIMIT(limit) - .GROUP() - .BY(subjectV) - .ORDER() - .BY(firstOneOfTitleV) - .build(defaultQueryBuilderOptions); - query = `PREFIX : <${defaultPrefix}> - ${fixSparqlOrder(query)} - `; - try { - const bindings = await doQuery(query); - return bindings.map((binding: any) => ({ - name: binding[firstOneOfTitleV.value]?.value, - value: binding[subjectV.value]?.value, - image: binding[imageV.value]?.value, - description: binding[descriptionV.value]?.value, - })); - } catch (e) { - console.error("Error finding entity by class", e); - return []; - } -}; diff --git a/apps/exhibition-live/components/utils/discover/index.ts b/apps/exhibition-live/components/utils/discover/index.ts deleted file mode 100644 index e19909a2..00000000 --- a/apps/exhibition-live/components/utils/discover/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./findEntityByClass"; -export * from "./findEntityByAuthorityIRI"; diff --git a/apps/exhibition-live/components/utils/gnd/findpersonWithinGND.ts b/apps/exhibition-live/components/utils/gnd/findpersonWithinGND.ts deleted file mode 100644 index 07928f5c..00000000 --- a/apps/exhibition-live/components/utils/gnd/findpersonWithinGND.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { QueryEngine } from "@comunica/query-sparql"; -import { BindingsStream } from "@comunica/types"; -import { Literal, NamedNode } from "@rdfjs/types"; - -import { gndPrefixes } from "./prefixes"; -import { prefixes2sparqlPrefixDeclaration } from "@slub/sparql-schema"; - -export type GNDSearchResultEntry = { - gndid: string; - literal: string; - score: number; -}; - -const searchPersonWithinGNDQuery = ( - searchString: string, - limit: number = 10, - type: string, -) => ` -${prefixes2sparqlPrefixDeclaration(gndPrefixes)} -SELECT DISTINCT ?gndid ?score ?literal WHERE -{ - (?gndid ?score ?literal) text:query "${searchString}~" . - ?gndid a gndo:${type} . -} LIMIT ${limit} -`; - -const findPersonWithinGND = async ( - searchString: string, - limit?: number, - classType?: string, -) => { - const myEngine = new QueryEngine(); - const bindingsStream: BindingsStream = await myEngine.queryBindings( - searchPersonWithinGNDQuery( - searchString, - limit, - classType || "DifferentiatedPerson", - ), - { - sources: ["http://gnd4c.digicult-verbund.de:3030/gndt/sparql"], - }, - ); - const results: GNDSearchResultEntry[] = []; - for (const binding of await bindingsStream.toArray()) { - results.push({ - gndid: (binding.get("gndid") as NamedNode).value, - literal: (binding.get("literal") as Literal).value, - score: parseFloat((binding.get("score") as Literal).value), - }); - } - return results; -}; - -export default findPersonWithinGND; diff --git a/apps/exhibition-live/components/utils/graph/jsonSchemaGraphInfuser.test.ts b/apps/exhibition-live/components/utils/graph/jsonSchemaGraphInfuser.test.ts deleted file mode 100644 index ad361d9c..00000000 --- a/apps/exhibition-live/components/utils/graph/jsonSchemaGraphInfuser.test.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { describe, expect, test } from "@jest/globals"; -import datasetFactory from "@rdfjs/dataset"; -import N3Parser from "@rdfjs/parser-n3"; -import { Dataset } from "@rdfjs/types"; -import fs from "fs"; -import { JSONSchema7 } from "json-schema"; -import dsExt from "rdf-dataset-ext"; -// @ts-ignore -import tbbt from "tbbt-ld/dist/tbbt.nq"; -import result01 from "../../../fixtures/tests/jsonSchemaGraphInfuser_01.json"; - -import { jsonSchemaGraphInfuser } from "./jsonSchemaGraphInfuser"; - -function sampleDataset() { - const input = fs.createReadStream(tbbt); - const parser = new N3Parser(); - - return dsExt.fromStream(datasetFactory.dataset(), parser.import(input)); -} - -const schemaStub = { - $defs: { - Address: { - type: "object", - properties: { - addressCountry: { - type: "string", - }, - addressRegion: { - type: "string", - }, - postalCode: { - type: "string", - }, - streetAddress: { - type: "string", - }, - }, - }, - Person: { - title: "Person", - description: "A human being", - type: "object", - properties: { - familyName: { - type: "string", - }, - givenName: { - type: "string", - }, - knows: { - type: "array", - items: { - $ref: "#/$defs/Person", - }, - }, - address: { - $ref: "#/$defs/Address", - }, - }, - }, - }, - $schema: "http://json-schema.org/draft-06/schema#", - $id: "https://example.com/person.schema.json", -}; - -describe("can get data via json schema", () => { - test("build from clownface", () => { - expect(sampleDataset()).toBeDefined(); - }); - - const baseIRI = "http://schema.org/"; - test("get from test schema", async () => { - const schema = { ...schemaStub, ...schemaStub.$defs.Person }; - const ds = await sampleDataset(); - const data = jsonSchemaGraphInfuser( - baseIRI, - "http://localhost:8080/data/person/leonard-hofstadter", - ds as Dataset, - schema as JSONSchema7, - { - omitEmptyArrays: true, - omitEmptyObjects: true, - maxRecursionEachRef: 1, - maxRecursion: 5, - }, - ); - expect(data).toStrictEqual(result01); - }); -}); diff --git a/apps/exhibition-live/components/utils/graph/jsonSchemaGraphInfuser.ts b/apps/exhibition-live/components/utils/graph/jsonSchemaGraphInfuser.ts deleted file mode 100644 index 3f631da0..00000000 --- a/apps/exhibition-live/components/utils/graph/jsonSchemaGraphInfuser.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { traverseGraphExtractBySchema } from "@slub/edb-graph-traversal"; - -export const jsonSchemaGraphInfuser: typeof traverseGraphExtractBySchema = - traverseGraphExtractBySchema; diff --git a/apps/exhibition-live/components/utils/mapping/mapByConfig.ts b/apps/exhibition-live/components/utils/mapping/mapByConfig.ts deleted file mode 100644 index c48cb09d..00000000 --- a/apps/exhibition-live/components/utils/mapping/mapByConfig.ts +++ /dev/null @@ -1,142 +0,0 @@ -import Ajv from "ajv"; -import cloneDeep from "lodash/cloneDeep"; -import get from "lodash/get"; -import isNil from "lodash/isNil"; -import set from "lodash/set"; -import jsonpath from "jsonpath"; - -import { - DeclarativeFlatMappings, - DeclarativeMappings, - StrategyContext, - strategyFunctionMap, -} from "./mappingStrategies"; -import { filterUndefOrNull } from "../core"; - -const getViaSourcePath = ( - sourceData: any, - sourcePath: string[] | string, -): any => { - if (Array.isArray(sourcePath)) { - return get(sourceData, sourcePath); - } - if (typeof sourcePath === "string") { - if (sourcePath.startsWith("$")) { - return jsonpath.query(sourceData, sourcePath); - } - return get(sourceData, sourcePath); - } -}; - -const getViaColumnPaths = ( - accessorFn: (col: number | string) => any, - columnPaths: string[] | number[], -): any => { - const values = columnPaths.map((path) => accessorFn(path)); - return values; -}; - -export const mapByConfigFlat = async ( - accessorFn: (col: number | string) => any, - targetData: any, - mappingConfig: DeclarativeFlatMappings, - strategyContext: StrategyContext, -): Promise => { - const newData = cloneDeep(targetData); //clone targetData to not mutate it accidentally - for (const { source, target, mapping } of mappingConfig) { - const { path: targetPath } = target; - if (!source?.columns || source.columns.length === 0) - throw new Error( - `No source path defined for mapping ${JSON.stringify(mapping)}`, - ); - const isList = source.columns.length === 1 && source.columns[0]; - if (!mapping?.strategy) { - //take value as is if no strategy is defined - const sourceValue = filterUndefOrNull( - getViaColumnPaths(accessorFn, source.columns), - ); - if (sourceValue.length === 0) continue; - if (isList) { - set(newData, targetPath, sourceValue[0]); - } else { - set(newData, targetPath, sourceValue); - } - } else { - const mappingFunction = strategyFunctionMap[mapping.strategy.id]; - if (typeof mappingFunction !== "function") { - throw new Error(`Strategy ${mapping.strategy.id} is not implemented`); - } - const strategyOptions = (mapping.strategy as any).options; - let value; - if (isList) { - value = await mappingFunction( - getViaColumnPaths(accessorFn, source.columns)[0], - get(newData, targetPath), - strategyOptions, - strategyContext, - ); - } else { - value = await mappingFunction( - getViaColumnPaths(accessorFn, source.columns), - get(newData, targetPath), - strategyOptions, - strategyContext, - ); - if (Array.isArray(value)) value = filterUndefOrNull(value); - } - if (!isNil(value)) set(newData, targetPath, value); - } - } - return newData; -}; - -export const mapByConfig = async ( - sourceData: Record, - targetData: any, - mappingConfig: DeclarativeMappings, - strategyContext: StrategyContext, -): Promise => { - const newData = cloneDeep(targetData); //clone targetData to not mutate it accidentally - const ajv = new Ajv(); - for (const { source, target, mapping } of mappingConfig) { - const { path: sourcePath, expectedSchema } = source; - const { path: targetPath } = target; - const hasSourcePath = source?.path && source.path.length > 0; - const sourceValue = hasSourcePath - ? getViaSourcePath(sourceData, sourcePath) - : sourceData; - if (isNil(sourceValue)) continue; - if (expectedSchema && !ajv.validate(expectedSchema, sourceValue)) { - if (strategyContext.options?.strictCheckTargetData) - throw new Error( - `Value does not match expected schema ${JSON.stringify( - expectedSchema, - )}`, - ); - console.warn( - `Value does not match expected schema ${JSON.stringify( - expectedSchema, - )}`, - ); - } else { - if (!mapping?.strategy) { - //take value as is if no strategy is defined - set(newData, targetPath, sourceValue); - } else { - const mappingFunction = strategyFunctionMap[mapping.strategy.id]; - if (typeof mappingFunction !== "function") { - throw new Error(`Strategy ${mapping.strategy.id} is not implemented`); - } - const strategyOptions = (mapping.strategy as any).options; - const value = await mappingFunction( - sourceValue, - get(newData, targetPath), - strategyOptions, - strategyContext, - ); - if (!isNil(value)) set(newData, targetPath, value); - } - } - } - return newData; -}; diff --git a/apps/exhibition-live/components/utils/sparql/index.ts b/apps/exhibition-live/components/utils/sparql/index.ts deleted file mode 100644 index 44cf0fe0..00000000 --- a/apps/exhibition-live/components/utils/sparql/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export * from "@slub/remote-query-implementations"; -export { - sparqlSelectFieldsQuery, - sparqlSelectViaFieldMappings, - jsonSchema2Select, - jsonSchema2construct, -} from "@slub/sparql-schema"; diff --git a/apps/exhibition-live/components/utils/types/index.ts b/apps/exhibition-live/components/utils/types/index.ts deleted file mode 100644 index 24c5e49e..00000000 --- a/apps/exhibition-live/components/utils/types/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./prefixes"; -export * from "./primaryFields"; diff --git a/apps/exhibition-live/components/utils/types/primaryFields.ts b/apps/exhibition-live/components/utils/types/primaryFields.ts deleted file mode 100644 index cfe995a9..00000000 --- a/apps/exhibition-live/components/utils/types/primaryFields.ts +++ /dev/null @@ -1,28 +0,0 @@ -export type FieldExtractDeclaration = - | string - | ((entry: T) => string) - | { path: string }; - -export type PrimaryField = Partial<{ - label: string; - description: string; - image: string; -}>; -export type PrimaryFieldExtract = Partial<{ - label: FieldExtractDeclaration; - description: FieldExtractDeclaration; - image: FieldExtractDeclaration; -}>; -export type PrimaryFieldDeclaration = { - [typeName: string]: PrimaryField; -}; - -export type PrimaryFieldExtractDeclaration = { - [typeName: string]: PrimaryFieldExtract; -}; - -export type PrimaryFieldResults = { - label: T | null; - description: T | null; - image: T | null; -}; diff --git a/apps/exhibition-live/cypress.config.ts b/apps/exhibition-live/cypress.config.ts new file mode 100644 index 00000000..2b646e4a --- /dev/null +++ b/apps/exhibition-live/cypress.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from "cypress"; + +export default defineConfig({ + e2e: { + baseUrl: "http://localhost:3000/", + setupNodeEvents(on, config) { + // implement node event listeners here + }, + }, + env: { + NEXT_PUBLIC_BASE_PATH: "/", + }, +}); diff --git a/apps/exhibition-live/cypress/e2e/create_exhibition.cy.ts b/apps/exhibition-live/cypress/e2e/create_exhibition.cy.ts new file mode 100644 index 00000000..09dd8e0c --- /dev/null +++ b/apps/exhibition-live/cypress/e2e/create_exhibition.cy.ts @@ -0,0 +1,51 @@ +import { clearAllIds } from "@jsonforms/core"; + +describe("create a simple exhibition (german)", () => { + it("will save all data correctly", () => { + cy.visit( + "/de/create/Exhibition?encID=aHR0cDovL29udG9sb2dpZXMuc2x1Yi1kcmVzZGVuLmRlL2V4aGliaXRpb24vZW50aXR5LzFmODQ2MzBkLWRhNzEtNDkyZS1hYmQxLTE0YzczYjA1NmRiZg==", + ); + cy.viewport(1920, 1080); + //clearAllIds(); + cy.wait(2000); + const titleInput = cy.get(`#${CSS.escape("#/properties/title4-input")}`); + titleInput.type("Gemälde von"); + titleInput.focus(); + cy.contains("p", "20 gefundene Suchergebnisse"); + titleInput.type("{downarrow}"); + titleInput.type("{downarrow}"); + titleInput.type("{downarrow}"); + + cy.get(".accept-button").click(); + cy.get("div.MuiDialogActions-root button").eq(0).click(); + cy.wait(2000); + const subtitleInput = cy.get( + `#${CSS.escape("#/properties/subtitle4-input")}`, + ); + subtitleInput.click(); + subtitleInput.type("2024"); + const originalTitleInput = cy.get( + `#${CSS.escape("#/properties/originalTitle4-input")}`, + ); + originalTitleInput.click(); + originalTitleInput.type("Frühjahrsausstellung"); + const genreInput = cy.get("label").contains("Genre").next(); + genreInput.click(); + genreInput.type("Stillleben"); + cy.get("button").contains("Genre neu anlegen").click(); + cy.get('svg[data-testid="SearchIcon"]').last().click(); + cy.get("button").contains("speichern & akzeptieren").click(); + cy.get(`div[data-testid="chip-exhibitionGenre.0-0"]`).contains( + "Stillleben", + ); + cy.get("button").contains("weiter").click(); + const placeInput = cy + .get("label") + .contains("Ausstellungsorte (Städte und Länder)") + .next(); + placeInput.click(); + placeInput.type("Dresden"); + cy.get('svg[data-testid="CheckIcon"]').first().click(); + cy.get('button[aria-label="speichern"]').click(); + }); +}); diff --git a/apps/exhibition-live/cypress/e2e/personList.cy.js b/apps/exhibition-live/cypress/e2e/personList.cy.js new file mode 100644 index 00000000..f2b64894 --- /dev/null +++ b/apps/exhibition-live/cypress/e2e/personList.cy.js @@ -0,0 +1,95 @@ +describe("Person List Error Check", () => { + it("should be able to create a new person", () => { + cy.visit("http://localhost:5173/de/list/Person"); + //bigger window size + cy.viewport(1920, 1080); + + cy.get("div:nth-child(3)>div:nth-child(1)>button:nth-child(1)").click({ + force: true, + }); + cy.findByLabelText("Name", { selector: "input", trim: true }).click({ + force: true, + }); + cy.findByLabelText("Name", { selector: "input", trim: true }).type( + "Adam Ries", + { delay: 1 }, + ); + cy.get("div:nth-child(1)>div:nth-child(2)>button:nth-child(1)").click({ + force: true, + }); + cy.get("textarea").eq(0).click({ force: true }); + cy.get("textarea") + .eq(0) + .type("Ein Mathematiker aus Annaberg", { delay: 0 }); + cy.findByLabelText("Geografischer Ort", { + selector: "input", + trim: true, + }).click({ force: true }); + cy.findByLabelText("Geografischer Ort", { + selector: "input", + trim: true, + }).type("Annaberg-Buch"); + cy.get('div[aria-label$="Annaberg-Buchholz"]') + .closest("li") + .find('svg[data-testid="CheckIcon"]') + .eq(0) + .click({ force: true }); + + cy.contains("h4", "Arbeitsorte") + .closest("div.MuiGrid-item") + .within(() => { + cy.get("input").eq(0).click(); + cy.get("input").eq(0).type("09"); + cy.get("input").eq(0).trigger("keydown", { keyCode: 9, which: 9 }); + cy.get("input").eq(1).type("02"); + cy.get("input").eq(1).trigger("keydown", { keyCode: 9, which: 9 }); + cy.get("input").eq(2).type("1878"); + cy.get("input").eq(2).trigger("keydown", { keyCode: 9, which: 9 }); + cy.get("input").eq(3).type("07"); + cy.get("input").eq(3).trigger("keydown", { keyCode: 9, which: 9 }); + cy.get("input").eq(4).type("02"); + cy.get("input").eq(4).trigger("keydown", { keyCode: 9, which: 9 }); + cy.get("input").eq(5).type("1879"); + + cy.get('svg[data-testid="CheckIcon"]').eq(0).click({ force: true }); + cy.contains("span", "Annaberg-Buchholz (9.2.1878 - 7.2.1879)").should( + "exist", + ); + }); + + //cy.screenshot(`createPerson-${(new Date()).getTime()}-${Cypress.env("COMMIT_SHA")}`); + + cy.get('button[aria-label="save"]').click({ force: true }); + cy.get("div#notistack-snackbar").should( + "have.text", + "erfolgreich gespeichert", + ); + cy.wait(1000); + //cy.get("div:nth-child(1)>div:nth-child(1)>div:nth-child(1)>div:nth-child(1)>button:nth-child(1)").click({ force: true}) + //cy.get("div.MuiTypography-h1")//.should('have.text',"Adam Ries") + + cy.screenshot( + `showPerson-${new Date().getTime()}-${Cypress.env("COMMIT_SHA")}`, + ); + }); + + it('should check for "Cannot read properties of null error', () => { + cy.visit("http://localhost:5173/de/list/Person"); + + cy.screenshot( + `useContext-${new Date().getTime()}-${Cypress.env("COMMIT_SHA")}`, + ); + + cy.on("uncaught:exception", () => { + // Listen for JavaScript errors + return false; + }); + + try { + cy.contains("h3", "Cannot read properties of null").should("not.exist"); + } catch (error) { + // This block will execute if the element is not found + cy.log("Error message not found, as expected."); + } + }); +}); diff --git a/apps/exhibition-live/cypress/support/commands.ts b/apps/exhibition-live/cypress/support/commands.ts new file mode 100644 index 00000000..9f51754d --- /dev/null +++ b/apps/exhibition-live/cypress/support/commands.ts @@ -0,0 +1,43 @@ +/// + +import "@testing-library/cypress/add-commands"; +// *********************************************** +// This example commands.ts shows you how to +// create various custom commands and overwrite +// existing commands. +// +// For more comprehensive examples of custom +// commands please read more here: +// https://on.cypress.io/custom-commands +// *********************************************** +// +// +// -- This is a parent command -- +// Cypress.Commands.add('login', (email, password) => { ... }) +// +//Cypress.Commands.add("getInput", (property: string) => { +// cy.get(`#${CSS.escape(`#/properties/${property}-input`)}`); +//}); +// +// -- This is a child command -- +// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) +// +// +// -- This is a dual command -- +// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) +// +// +// -- This will overwrite an existing command -- +// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) +// +/*declare global { + namespace Cypress { + interface Chainable { + getInput(property: string): Chainable; + // login(email: string, password: string): Chainable + // drag(subject: string, options?: Partial): Chainable + // dismiss(subject: string, options?: Partial): Chainable + // visit(originalFn: CommandOriginalFn, url: string, options: Partial): Chainable + } + } +}*/ diff --git a/apps/exhibition-live/cypress/support/e2e.ts b/apps/exhibition-live/cypress/support/e2e.ts new file mode 100644 index 00000000..b64ec7a6 --- /dev/null +++ b/apps/exhibition-live/cypress/support/e2e.ts @@ -0,0 +1,16 @@ +// *********************************************************** +// This example support/e2e.ts is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +import "./commands"; diff --git a/apps/exhibition-live/index.html b/apps/exhibition-live/index.html new file mode 100644 index 00000000..240b697b --- /dev/null +++ b/apps/exhibition-live/index.html @@ -0,0 +1,12 @@ + + + + + + Ausstellungsdatenbank + + +
+ + + diff --git a/apps/exhibition-live/next.config.js b/apps/exhibition-live/next.config.js index 980f1abb..61ff3ac9 100644 --- a/apps/exhibition-live/next.config.js +++ b/apps/exhibition-live/next.config.js @@ -1,17 +1,44 @@ +const removeImports = require("next-remove-imports")({ + test: /node_modules([\s\S]*?)\.(tsx|ts|js|mjs|jsx)$/, + matchImports: "\\.(less|css|scss|sass|styl)$", +}); + +const withBundleAnalyzer = require("@next/bundle-analyzer")({ + enabled: process.env.ANALYZE === "true", +}); + /** @type {import('next').NextConfig} */ -const nextConfig = { +const nextConfig = removeImports({ reactStrictMode: true, output: "export", + modularizeImports: { + "@mui/icons-material": { transform: "@mui/icons-material/{{member}}" }, + lodash: { transform: "lodash/{{member}}" }, + "lodash-es": { transform: "lodash-es/{{member}}" }, + }, + experimental: { + externalDir: true, + optimizePackageImports: [ + "@mui/material", + "@mui/icons-material", + "@mui/lab", + ], + }, images: { unoptimized: true, }, - basePath: process.env.NEXT_PUBLIC_BASE_PATH || "/exhibition-live", + basePath: process.env.NEXT_PUBLIC_BASE_PATH || "", publicRuntimeConfig: { NEXT_PUBLIC_GAPI_OAUTH_CLIENT_ID: process.env.NEXT_PUBLIC_GAPI_OAUTH_CLIENT_ID, - NEXT_PUBLIC_BASE_PATH: - process.env.NEXT_PUBLIC_BASE_PATH || "/exhibition-live", + NEXT_PUBLIC_BASE_PATH: process.env.NEXT_PUBLIC_BASE_PATH || "", + SPARQL_ENDPOINT: process.env.SPARQL_ENDPOINT, + SPARQL_ENDPOINT_LABEL: process.env.SPARQL_ENDPOINT_LABEL, + SPARQL_ENDPOINT_PROVIDER: process.env.SPARQL_ENDPOINT_PROVIDER, + SPARQL_ENDPOINT_USERNAME: process.env.SPARQL_ENDPOINT_USERNAME, + SPARQL_ENDPOINT_PASSWORD: process.env.SPARQL_ENDPOINT_PASSWORD, + SPARQL_ENDPOINT_TOKEN: process.env.SPARQL_ENDPOINT_TOKEN, }, -}; +}); -module.exports = nextConfig; +module.exports = withBundleAnalyzer(nextConfig); diff --git a/apps/exhibition-live/next.config.standalone.js b/apps/exhibition-live/next.config.standalone.js index 2d6973cc..83d10fdd 100644 --- a/apps/exhibition-live/next.config.standalone.js +++ b/apps/exhibition-live/next.config.standalone.js @@ -1,3 +1,8 @@ +const removeImports = require("next-remove-imports")({ + test: /node_modules([\s\S]*?)\.(tsx|ts|js|mjs|jsx)$/, + matchImports: "\\.(less|css|scss|sass|styl)$", +}); + /** @type {import('next').NextConfig} */ const nextConfig = { reactStrictMode: true, @@ -10,7 +15,13 @@ const nextConfig = { NEXT_PUBLIC_GAPI_OAUTH_CLIENT_ID: process.env.NEXT_PUBLIC_GAPI_OAUTH_CLIENT_ID, NEXT_PUBLIC_BASE_PATH: process.env.NEXT_PUBLIC_BASE_PATH, + SPARQL_ENDPOINT: process.env.SPARQL_ENDPOINT, + SPARQL_ENDPOINT_LABEL: process.env.SPARQL_ENDPOINT_LABEL, + SPARQL_ENDPOINT_PROVIDER: process.env.SPARQL_ENDPOINT_PROVIDER, + SPARQL_ENDPOINT_USERNAME: process.env.SPARQL_ENDPOINT_USERNAME, + SPARQL_ENDPOINT_PASSWORD: process.env.SPARQL_ENDPOINT_PASSWORD, + SPARQL_ENDPOINT_TOKEN: process.env.SPARQL_ENDPOINT_TOKEN, }, }; -module.exports = nextConfig; +module.exports = removeImports(nextConfig); diff --git a/apps/exhibition-live/package.json b/apps/exhibition-live/package.json index bbd97c5e..63fec9d6 100644 --- a/apps/exhibition-live/package.json +++ b/apps/exhibition-live/package.json @@ -4,8 +4,10 @@ "private": true, "scripts": { "dev": "next dev", + "dev:vite": "vite --host", "build": "next build", - "start": "next start", + "demo": "bun run dev:vite", + "start": "next start || bunx serve@latest -p 3000 ./out", "lint": "next lint", "test": "NODE_OPTIONS=--experimental-vm-modules jest -w", "test:jsonSchema2Construct": "NODE_OPTIONS=--experimental-vm-modules jest --watch --runTestsByPath components/utils/sparql/jsonSchema2construct.test.ts ", @@ -27,63 +29,74 @@ "docker:run": "docker run -p 3000:3000 adb-next" }, "dependencies": { - "@apidevtools/json-schema-ref-parser": "^9.1.0", "@comunica/query-sparql": "^2.5.2", "@comunica/types": "^2.8.2", "@ebay/nice-modal-react": "^1.2.13", "@egjs/hammerjs": "^2.0.17", "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", - "@inovua/reactdatagrid-community": "^5.8.1", - "@jsonforms/core": "3.1.0", - "@jsonforms/material-renderers": "3.1.0", - "@jsonforms/react": "3.1.0", + "@jsonforms/core": "3.4.0", + "@jsonforms/material-renderers": "3.4.0", + "@jsonforms/react": "3.4.0", "@mui/icons-material": "^5.11.0", "@mui/lab": "^5.0.0-alpha.115", "@mui/material": "^5.11.4", - "@mui/material-next": "^6.0.0-alpha.103", "@mui/styles": "^5.14.15", "@mui/system": "^5.14.15", - "@mui/utils": "^5.14.15", + "@mui/base": "^5.0.0-beta.40", "@mui/x-date-pickers": "^6.16.3", - "@phntms/use-local-state": "^0.1.4", + "@reduxjs/toolkit": "^2.2.3", + "react-redux": "^9.1.1", "@rdfjs/data-model": "^2.0.2", - "@rdfjs/dataset": "^2.0.1", + "@rdfjs/dataset": "^2.0.2", "@rdfjs/namespace": "^2.0.0", "@rdfjs/parser-n3": "^2.0.1", "@rdfjs/types": "^1.1.0", "@react-oauth/google": "^0.12.1", "@slub/edb-core-utils": "workspace:*", "@slub/edb-graph-traversal": "workspace:*", + "@slub/edb-charts": "workspace:*", + "@slub/edb-debug-utils": "workspace:*", "@slub/remote-query-implementations": "workspace:*", "@slub/sparql-schema": "workspace:*", "@slub/sparql-db-impl": "workspace:*", - "@tabler/icons": "^2.38.0", - "@tanstack/react-query": "^4.24.6", - "@tanstack/react-query-devtools": "^5.8.2", + "@slub/edb-ui-utils": "workspace:*", + "@slub/edb-kxp-utils": "workspace:*", + "@slub/edb-state-hooks": "workspace:*", + "@slub/edb-markdown-renderer": "workspace:*", + "@slub/edb-basic-components": "workspace:*", + "@slub/edb-advanced-components": "workspace:*", + "@slub/edb-virtualized-components": "workspace:*", + "@slub/edb-table-components": "workspace:*", + "@slub/edb-layout-renderer": "workspace:*", + "@slub/edb-linked-data-renderer": "workspace:*", + "@slub/edb-basic-renderer": "workspace:*", + "@slub/edb-vis-timeline": "workspace:*", + "@slub/edb-authorities": "workspace:*", + "@slub/edb-data-mapping": "workspace:*", + "@slub/edb-default-theme": "workspace:*", + "@slub/edb-sparnatural": "workspace:*", + "@slub/exhibition-schema": "workspace:*", + "@slub/kulinarik-schema": "workspace:*", + "@tanstack/table-core": "^8.16.0", + "@tanstack/react-query": "^4.36.1", + "@tanstack/react-query-devtools": "^4.36.1", "@tpluscode/rdf-ns-builders": "^2.0.1", - "@tpluscode/rdfine": "^0.5.41", - "@tpluscode/sparql-builder": "^0.3.31", "@triply/yasgui": "^4.2.28", "@uiw/react-markdown-preview": "^5.1.1", - "@uiw/react-md-editor": "4.0.4", + "@uiw/react-md-editor": "^4.0.4", "react-remark": "latest", - "rehype-katex": "latest", "rehype-stringify": "latest", "rehype-parse": "latest", - "rehype-mermaid": "latest", "rehype-video": "latest", "rehype-sanitize": "latest", "remark-rehype": "latest", "rehype-document": "latest", - "remark-math": "^6.0.0", "@visx/responsive": "^3.3.0", "ajv": "^8.12.0", "async-oxigraph": "^0.0.6", "component-emitter": "^1.3.0", "color-thief-ts": "^1.1.1", - "csstype": "^3.1.2", - "d3": "^7.8.5", "dayjs": "^1.11.7", "dot": "2.0.0-beta.1", "export-to-csv": "^1.2.1", @@ -92,13 +105,12 @@ "graphql-tag": "^2.12.6", "html-react-parser": "^3.0.7", "i18next": "^23.7.7", - "i18next-http-backend": "^2.4.2", - "i18next-resources-to-backend": "^1.2.0", + "i18next-http-backend": "^2.5.1", "json-schema": "^0.4.0", + "json-schema-to-ts": "^3.0.1", "jsonld": "^8.1.0", "jsonld-context-parser": "^2.3.3", "jsonpath": "^1.1.1", - "jsonref": "^8.0.8", "keycharm": "^0.4.0", "leaflet": "^1.9.3", "lodash": "^4.17.21", @@ -106,7 +118,7 @@ "moment": "^2.29.4", "mui-image": "^1.0.7", "n3": "^1.16.3", - "next": "^14.0.3", + "next": "^14.2.5", "next-i18next": "^15.0.0", "next-language-detector": "^1.1.0", "notistack": "^3.0.1", @@ -118,17 +130,15 @@ "rdf-js": "^4.0.2", "react": "18.2.0", "react-collapse-pane": "^3.0.1", - "react-device-detect": "^2.2.3", "react-dom": "18.2.0", + "react-router-dom": "^6.23.1", "react-i18next": "^13.5.0", - "react-is": "^18.2.0", "react-json-view-lite": "^0.9.4", - "react-markdown": "^9.0.1", "react-virtuoso": "^4.6.2", "recharts": "^2.9.3", "sparql-http-client": "^2.4.2", "string-to-stream": "^3.0.1", - "styled-components": "^5.3.6", + "turndown": "^7.1.3", "uuid": "^9.0.0", "vis-data": "^7.1.8", "vis-timeline": "^7.7.3", @@ -138,6 +148,7 @@ }, "devDependencies": { "@babel/core": "^7.20.12", + "@esbuild-plugins/node-globals-polyfill": "^0.2.3", "@graphql-codegen/cli": "^3.0.0", "@graphql-codegen/typescript": "^3.0.0", "@graphql-codegen/typescript-graphql-request": "^4.5.8", @@ -145,14 +156,17 @@ "@graphql-codegen/typescript-react-query": "^4.1.0", "@graphql-codegen/typescript-resolvers": "^3.0.0", "@jest/globals": "^29.3.1", - "@storybook/addon-docs": "^8.0.0-rc.1", - "@storybook/addon-essentials": "^8.0.0-rc.1", - "@storybook/addon-links": "^8.0.0-rc.1", - "@storybook/blocks": "^8.0.0-rc.1", - "@storybook/nextjs": "^8.0.0-rc.1", - "@storybook/react": "^8.0.0-rc.1", + "@next/bundle-analyzer": "^14.2.3", + "@storybook/addon-docs": "^8.1.5", + "@storybook/addon-essentials": "^8.1.5", + "@storybook/addon-links": "^8.1.5", + "storybook-addon-next-router": "^4.0.2", + "@storybook/blocks": "^8.1.5", + "@storybook/nextjs": "^8.1.5", + "@storybook/react": "^8.1.5", "@storybook/storybook-deployer": "^2.8.16", - "@types/d3": "^7.4.3", + "@storybook/testing-react": "^2.0.1", + "@testing-library/cypress": "^10.0.2", "@types/dot": "^1.1.6", "@types/gapi": "^0.0.47", "@types/json-schema": "^7.0.14", @@ -163,33 +177,43 @@ "@types/node": "18.11.18", "@types/rdf-dataset-ext": "^1.0.3", "@types/rdfjs__dataset": "^2.0.0", + "@types/rdfjs__data-model": "^2", "@types/rdfjs__namespace": "^2.0.8", "@types/rdfjs__parser-jsonld": "^1.2.5", "@types/rdfjs__parser-n3": "^1.1.5", "@types/react": "^18.2.33", "@types/react-dom": "^18.2.14", "@types/sparql-http-client": "^2.2.8", + "@types/turndown": "latest", "@types/uuid": "^9.0.0", "@zazuko/rdf-vocabularies": "^2023.1.19", "babel-loader": "^8.3.0", "buffer": "^6.0.3", + "cypress": "^13.2.0", "clownface": "^1.5.1", "eslint-config-edb": "workspace:*", + "eslint-plugin-react-refresh": "^0.4.7", "@slub/edb-core-types": "workspace:*", + "@slub/edb-global-types": "workspace:*", + "@slub/json-schema-utils": "workspace:*", "file-loader": "^6.2.0", "jest": "^29.3.1", "json-schema-faker": "^0.5.0-rcv.46", - "next-remove-imports": "^1.0.8", + "next-remove-imports": "^1.0.12", "process": "^0.11.10", "safe-identifier": "^0.4.2", "sass": "^1.68.0", - "storybook": "^8.0.0-rc.1", + "storybook": "^8.1.5", "stream-browserify": "^3.0.0", "tbbt-ld": "^1.1.0", "ts-jest": "^29.0.5", "ts-morph": "^17.0.1", "ts-node": "^10.9.1", "typescript": "5.1.6", - "webpack": "^5.75.0" + "webpack": "^5.75.0", + "vite": "^5.2.0", + "@vitejs/plugin-react-swc": "^3.5.0", + "mermaid": "^10.9.1", + "mdx-mermaid": "^2.0.0" } } diff --git a/apps/exhibition-live/pages/[locale]/create/[typeName].tsx b/apps/exhibition-live/pages/[locale]/create/[typeName].tsx index 3a2df105..219d0178 100644 --- a/apps/exhibition-live/pages/[locale]/create/[typeName].tsx +++ b/apps/exhibition-live/pages/[locale]/create/[typeName].tsx @@ -1,21 +1,20 @@ import Head from "next/head"; import { useSearchParams } from "next/navigation"; -import { useRouter } from "next/router"; -import React, { useCallback, useEffect, useMemo, useState } from "react"; +import React, { useEffect, useMemo, useState } from "react"; import TypedForm from "../../../components/content/main/TypedForm"; -import { sladb, slent } from "../../../components/form/formConfigs"; import { MainLayout } from "../../../components/layout/main-layout"; -import schema from "../../../public/schema/Exhibition.schema.json"; -import { BASE_IRI } from "../../../components/config"; -import { v4 as uuidv4 } from "uuid"; -import { decodeIRI } from "../../../components/utils/core"; import { useTranslation } from "next-i18next"; import { getI18nProps, mixinStaticPathsParams } from "../../../components/i18n"; -import { useSettings } from "../../../components/state/useLocalSettings"; -import { useFormEditor } from "../../../components/state"; -import { Button, Hidden, ToggleButton } from "@mui/material"; +import { Button, Hidden } from "@mui/material"; import { Visibility, VisibilityOff } from "@mui/icons-material"; +import { decodeIRI } from "@slub/edb-core-utils"; +import { + useAdbContext, + useFormEditor, + useSettings, +} from "@slub/edb-state-hooks"; +import { schema } from "@slub/exhibition-schema"; type Props = { typeName: string; @@ -41,21 +40,23 @@ export async function getStaticProps(ctx) { }; } export default (props: Props) => { - const router = useRouter(); const { t } = useTranslation("translation"); const { typeName } = props; - const classIRI: string | undefined = useMemo( - () => (typeof typeName === "string" ? sladb(typeName).value : undefined), - [typeName], + + const { typeNameToTypeIRI, createEntityIRI } = useAdbContext(); + const typeIRI: string | undefined = useMemo( + () => + typeof typeName === "string" ? typeNameToTypeIRI(typeName) : undefined, + [typeName, typeNameToTypeIRI], ); - const [entityIRI, setEntityIRI] = useState(`${BASE_IRI}${uuidv4()}`); + const [entityIRI, setEntityIRI] = useState(); const searchParam = useSearchParams(); useEffect(() => { const encID = searchParam.get("encID"); const id = typeof encID === "string" ? decodeIRI(encID) : undefined; - const newURI = id || `${BASE_IRI}${typeName}-${uuidv4()}`; + const newURI = id || createEntityIRI(typeName); setEntityIRI(newURI); - }, [setEntityIRI, typeName, searchParam]); + }, [setEntityIRI, typeName, searchParam, createEntityIRI]); const title = `Neue ${t(typeName)} anlegen - Ausstellungserfassung`; const { features } = useSettings(); @@ -81,13 +82,13 @@ export default (props: Props) => { } > - {classIRI && typeName && ( + {typeIRI && typeName && ( <> )} diff --git a/apps/exhibition-live/pages/[locale]/list/[typeName].tsx b/apps/exhibition-live/pages/[locale]/list/[typeName].tsx index f4b8cad5..49e51b9f 100644 --- a/apps/exhibition-live/pages/[locale]/list/[typeName].tsx +++ b/apps/exhibition-live/pages/[locale]/list/[typeName].tsx @@ -1,12 +1,12 @@ import Head from "next/head"; -import { useRouter } from "next/router"; import React from "react"; import { MainLayout } from "../../../components/layout/main-layout"; -import { TypedList } from "../../../components/content/list/TypedList"; -import schema from "../../../public/schema/Exhibition.schema.json"; import { useTranslation } from "next-i18next"; import { getI18nProps, mixinStaticPathsParams } from "../../../components/i18n"; +import { schema } from "@slub/exhibition-schema"; +import { tableConfig } from "../../../components/config/tableConfig"; +import { SemanticTable } from "@slub/edb-table-components"; type Props = { typeName: string; @@ -45,7 +45,7 @@ export default (props: Props) => { - + ); diff --git a/apps/exhibition-live/pages/[locale]/listInfinite/[typeName].tsx b/apps/exhibition-live/pages/[locale]/listInfinite/[typeName].tsx deleted file mode 100644 index 0db7102e..00000000 --- a/apps/exhibition-live/pages/[locale]/listInfinite/[typeName].tsx +++ /dev/null @@ -1,51 +0,0 @@ -import Head from "next/head"; -import { useRouter } from "next/router"; -import React from "react"; - -import { MainLayout } from "../../../components/layout/main-layout"; -import schema from "../../../public/schema/Exhibition.schema.json"; -import { TypedInfiniteList } from "../../../components/content/main/TypedInfiniteList"; -import { getI18nProps, mixinStaticPathsParams } from "../../../components/i18n"; - -type Props = { - typeName: string; -}; -export async function getStaticPaths() { - const paths = mixinStaticPathsParams( - Object.keys(schema.$defs || {}).map((typeName) => ({ - params: { typeName }, - })), - ); - - return { paths, fallback: false }; -} - -export async function getStaticProps(ctx) { - const params = ctx?.params || {}; - const typeName = params.typeName; - return { - props: { - typeName, - ...getI18nProps(ctx), - }, - }; -} -export default (props: Props) => { - const router = useRouter(); - const { typeName } = props; - const title = `Ausstellungserfassung - ${typeName}`; - - return ( - <> - - ${title} - - - - - - - - - ); -}; diff --git a/apps/exhibition-live/pages/_app.tsx b/apps/exhibition-live/pages/_app.tsx index 6f47a2e8..3eb3b048 100644 --- a/apps/exhibition-live/pages/_app.tsx +++ b/apps/exhibition-live/pages/_app.tsx @@ -1,30 +1,49 @@ -import "../styles/globals.css"; +import "vis-timeline/styles/vis-timeline-graph2d.css"; import "../styles/jquery.typeahead.min.css"; import "../styles/jquery-ui.min.css"; import "../styles/highlight.min.css"; import "../styles/tooltipster.bundle.min.css"; import "../styles/tooltipster-sideTip-shadow.min.css"; -import "../styles/layout.css"; -import "../styles/temp.css"; +import "@uiw/react-markdown-preview/markdown.css"; +import "@uiw/react-md-editor/markdown-editor.css"; +import "@triply/yasgui/build/yasgui.min.css"; import "leaflet/dist/leaflet.css"; +import "react-json-view-lite/dist/index.css"; -import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import type { AppProps } from "next/app"; -import ThemeComponent from "../components/theme/ThemeComponent"; import NiceModal from "@ebay/nice-modal-react"; import { SnackbarProvider } from "notistack"; -import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; import { appWithTranslation, UserConfig, useTranslation } from "next-i18next"; import nextI18NextConfig from "../next-i18next.config"; import { GoogleOAuthProvider } from "@react-oauth/google"; -import { AdbProvider } from "../components/provider/adbContext"; import { LocalizationProvider } from "@mui/x-date-pickers"; import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; import dayjs from "dayjs"; import "dayjs/locale/de"; import "dayjs/locale/en"; import { useEffect } from "react"; +import { Provider } from "react-redux"; +import { OptionalLiveDemoEndpoint } from "../components/state"; +import getConfig from "next/config"; +import { BASE_IRI, PUBLIC_BASE_PATH } from "../components/config"; +import { + AdbProvider, + QueryClient, + QueryClientProvider, + store, +} from "@slub/edb-state-hooks"; +import { EditEntityModal } from "../components/form/edit/EditEntityModal"; +import { useRouter } from "next/router"; +import { exhibitionConfig } from "../components/config/exhibitionAppConfig"; +import { envToSparqlEndpoint } from "@slub/edb-core-utils"; +import { EntityDetailModal } from "@slub/edb-advanced-components"; +import { SemanticJsonFormNoOps } from "@slub/edb-linked-data-renderer"; +import { SimilarityFinder } from "../components/form/similarity-finder"; +import { useSearchParams } from "next/navigation"; +import { ModRouter } from "@slub/edb-global-types"; +import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; +import { ThemeComponent } from "@slub/edb-default-theme"; export const queryClient = new QueryClient(); const QueryClientProviderWrapper = ({ @@ -36,6 +55,15 @@ const QueryClientProviderWrapper = ({ {children} ); }; + +const sparqlEndpoint = envToSparqlEndpoint(getConfig().publicRuntimeConfig); + +const useNextRouterHook: () => ModRouter = () => { + const { query, asPath, push, replace, pathname } = useRouter(); + const searchParams = useSearchParams(); + return { query, asPath, push, replace, pathname, searchParams }; +}; + function App({ Component, pageProps }: AppProps) { const { i18n } = useTranslation(); useEffect(() => { @@ -44,21 +72,42 @@ function App({ Component, pageProps }: AppProps) { return ( - - - - + + + - {} - - - - - + + + + {} + + + + + + + + ); } +// @ts-ignore export default appWithTranslation(App, nextI18NextConfig as any as UserConfig); diff --git a/apps/exhibition-live/pages/_document.tsx b/apps/exhibition-live/pages/_document.tsx index ffc3f3cc..3d27ee44 100644 --- a/apps/exhibition-live/pages/_document.tsx +++ b/apps/exhibition-live/pages/_document.tsx @@ -4,7 +4,7 @@ export default function Document() { return ( - +
diff --git a/apps/exhibition-live/public/locales/de/table.json b/apps/exhibition-live/public/locales/de/table.json index a51a3d37..4b675518 100644 --- a/apps/exhibition-live/public/locales/de/table.json +++ b/apps/exhibition-live/public/locales/de/table.json @@ -49,5 +49,9 @@ "relatedCorporation": "Bezug zu Körperschaften", "exhibitionType": "Art", "exhibitionCategory": "Kategorie", - "exhibitionSeries": "Ausstellungsreihe" + "exhibitionSeries": "Ausstellungsreihe", + "exposedArtists": "Ausgestellte Künstler:innen", + "curators": "Kurator:innen", + "organizers": "Organisator:innen", + "catalogs": "Kataloge" } diff --git a/apps/exhibition-live/public/locales/de/translation.json b/apps/exhibition-live/public/locales/de/translation.json index 87e5866a..54f5bad3 100644 --- a/apps/exhibition-live/public/locales/de/translation.json +++ b/apps/exhibition-live/public/locales/de/translation.json @@ -13,6 +13,7 @@ "export": "Export", "list": "auflisten", "List": "Liste", + "Tag": "Schlagwort", "exhibition database": "Ausstellungsdatenbank", "create new": "{{item}} neu anlegen", "Exhibition": "Ausstellung", @@ -38,6 +39,7 @@ "ExhibitionExponat": "Exponat", "ExhibitionExponat_plural": "Exponate", "ExhibitionSeries": "Ausstellungsreihe", + "ResourceType": "Art der Ressource", "ExhibitionSeries_plural": "Ausstellungsreihen", "GeographicLocation": "Geographische Position", "GeographicLocation_plural": "Geographische Positionen", @@ -61,17 +63,21 @@ "CorporationRole_plural": "Rollen von Organisationen", "EventType": "Ereignisart", "EventType_plural": "Ereignisarten", + "Id Authority": "Normdaten", "edit entry": "Eintrag beareiten", "line chart": "Liniendiagramm", "timeline": "Zeitstrahl", "delete selected entries": "lösche ausgewählte {{count}} Einträge", "will remove entries": "{{count}} Einträge werden gelöscht", + "removed": "entfernt", + "about to remove": "dabei zu entfernen", "actions": "Aktionen", "successfully removed entries": "Erfolgreich {{count}} Einträge entfernt", "move selected entries to trash": "Ausgewählte {{count}} Einträge in den Papierkorb verschieben", "will move entries to trash": "{{count}} Einträge werden in den Papierkorb verschoben", "loading typename": "Lade {{typeName}}", "reloaded": "neu geladen", + "reload": "neu laden", "no hits": "keine Treffer", "no suggestions": "keine Vorschläge", "search delivered no results": "Die Suche ergab keine Treffer", @@ -89,5 +95,10 @@ "confirm-mapping-dialog-message": "Sie können die Daten aus der Abbildung in die Datenbank übernehmen, Entschieden Sie ob sie die bereits eingegebenen Datet überscheiben oder intelligent zusammenführen wollen.", "merge data": "Daten zusammenführen", "replace data": "Daten überschreiben", - "unknown": "unbekannt" + "unknown": "unbekannt", + "successfully saved": "erfolgreich gespeichert", + "error while saving": "Fehler beim Speichern", + "saved": "gespeichert", + "remove selection": "Auswahl entfernen", + "no selection": "keine Auswahl getroffen" } diff --git a/apps/exhibition-live/public/locales/en/table.json b/apps/exhibition-live/public/locales/en/table.json index c1e7259f..c359cfa9 100644 --- a/apps/exhibition-live/public/locales/en/table.json +++ b/apps/exhibition-live/public/locales/en/table.json @@ -49,5 +49,9 @@ "relatedCorporation": "related corporation", "exhibitionType": "type", "exhibitionCategory": "category", - "exhibitionSeries": "series" + "exhibitionSeries": "series", + "exposedArtists": "exposed artists", + "curators": "curators", + "organizers": "organizers", + "catalogs": "catalogs" } diff --git a/apps/exhibition-live/public/locales/en/translation.json b/apps/exhibition-live/public/locales/en/translation.json index e3de9a19..e6c5d5b8 100644 --- a/apps/exhibition-live/public/locales/en/translation.json +++ b/apps/exhibition-live/public/locales/en/translation.json @@ -13,6 +13,7 @@ "export": "export", "list": "list", "List": "list", + "Tag": "Tag", "exhibition database": "Exhibition Database", "create new": "create new {{item}}", "Exhibition": "Exhibition", @@ -38,6 +39,7 @@ "ExhibitionExponat": "exhibition exponat", "ExhibitionExponat_plural": "exhibition exponats", "ExhibitionSeries": "exhibition series", + "ResourceType": "resource type", "ExhibitionSeries_plural": "exhibition series", "GeographicLocation": "geographic location", "GeographicLocation_plural": "geographic locations", @@ -66,12 +68,15 @@ "timeline": "timeline", "delete selected entries": "delete selected {{count}} entries", "will remove entries": "{{count}} entries will be removed", + "removed": "removed", + "about to remove": "about to move", "actions": "actions", "successfully removed entries": "Successfully removed {{count}} entries", "move selected entries to trash": "move {{count}} selected entries to trash", "will move entries to trash": "Will move {{count}} entries to trash", "loading typename": "Loading {{typeName}}", "reloaded": "reloaded", + "reload": "reload", "no hits": "no hits", "no suggestions": "no suggestions", "search delivered no results": "Search delivered no results", @@ -89,5 +94,10 @@ "confirm-mapping-dialog-message": "You can accept the data from the mapping into the database. Decide if you want to overwrite the already entered data or merge it intelligently.", "merge data": "merge data", "replace data": "overwrite data", - "unknown": "unknown" + "unknown": "unknown", + "successfully saved": "successfully saved", + "error while saving": "error while saving", + "saved": "saved", + "remove selection": "remove selection", + "no selection": "no selection made" } diff --git a/apps/exhibition-live/public/schema/Exhibition.schema.json b/apps/exhibition-live/public/schema/Exhibition.schema.json index e928e324..9606598e 100644 --- a/apps/exhibition-live/public/schema/Exhibition.schema.json +++ b/apps/exhibition-live/public/schema/Exhibition.schema.json @@ -255,12 +255,6 @@ }, "description": { "type": "string" - }, - "tags": { - "type": "array", - "items": { - "$ref": "#/$defs/Tag" - } } } }, @@ -389,7 +383,12 @@ }, "dateModifier": { "type": "integer", + "title": "Art der Zeitangabe", "oneOf": [ + { + "const": 0, + "title": "exakt" + }, { "const": 1, "title": "ca." @@ -416,7 +415,12 @@ }, "dateModifier": { "type": "integer", + "title": "Art der Zeitangabe", "oneOf": [ + { + "const": 0, + "title": "exakt" + }, { "const": 1, "title": "ca." @@ -539,7 +543,12 @@ }, "dateModifier": { "type": "integer", + "title": "Art der Zeitangabe", "oneOf": [ + { + "const": 0, + "title": "exakt" + }, { "const": 1, "title": "ca." @@ -566,7 +575,12 @@ }, "dateModifier": { "type": "integer", + "title": "Art der Zeitangabe", "oneOf": [ + { + "const": 0, + "title": "exakt" + }, { "const": 1, "title": "ca." @@ -603,6 +617,10 @@ "$ref": "#/$defs/Genre" } }, + "parent": { + "title": "Übergeordnete Ausstellung", + "$ref": "#/$defs/Exhibition" + }, "externalId": { "type": "string", "maxLength": 50 @@ -617,6 +635,9 @@ "type": "string", "maxLength": 300 }, + "placesUnknown": { + "type": "boolean" + }, "places": { "type": "array", "items": { @@ -635,12 +656,30 @@ "$ref": "#/$defs/Tag" } }, + "exposedArtists": { + "type": "array", + "items": { + "$ref": "#/$defs/Person" + } + }, + "curators": { + "type": "array", + "items": { + "$ref": "#/$defs/Person" + } + }, "involvedPersons": { "type": "array", "items": { "$ref": "#/$defs/InvolvedPerson" } }, + "organizers": { + "type": "array", + "items": { + "$ref": "#/$defs/Corporation" + } + }, "involvedCorporations": { "type": "array", "items": { @@ -687,6 +726,12 @@ "$ref": "#/$defs/ExhibitionExponat" } }, + "catalogs": { + "type": "array", + "items": { + "$ref": "#/$defs/Resource" + } + }, "resources": { "type": "array", "items": { diff --git a/apps/exhibition-live/public/schema/Exhibition.schema_shape_multilingual.ttl b/apps/exhibition-live/public/schema/Exhibition.schema_shape_multilingual.ttl new file mode 100644 index 00000000..48d02a3f --- /dev/null +++ b/apps/exhibition-live/public/schema/Exhibition.schema_shape_multilingual.ttl @@ -0,0 +1,1107 @@ +@prefix : . +@prefix rdf: . +@prefix rdfs: . +@prefix sh: . +@prefix xsd: . +@prefix sparna: . +@prefix sparco: . +@prefix dash: . +@prefix this: . +@prefix volipi: . + +:Tag a rdfs:Class ; +. +:Occupation a rdfs:Class ; +. +:SeriesType a rdfs:Class ; +. +:ExhibitionSeries a rdfs:Class ; +. +:Person a rdfs:Class ; +. +:Workplace a rdfs:Class ; +. +:Location a rdfs:Class ; +. +:PersonRole a rdfs:Class ; +. +:CorporationRole a rdfs:Class ; +. +:Place a rdfs:Class ; +. +:EventType a rdfs:Class ; +. +:Corporation a rdfs:Class ; +. +:ResourceType a rdfs:Class ; +. +:Resource a rdfs:Class ; +. +:ExponatsAndPersons a rdfs:Class ; +. +:ExponatsAndCorporations a rdfs:Class ; +. +:ExhibitionExponat a rdfs:Class ; +. +:ExhibitionCategory a rdfs:Class ; +. +:InvolvedPerson a rdfs:Class ; +. +:InvolvedCorporation a rdfs:Class ; +. +:Genre a rdfs:Class ; +. +:Exhibition a rdfs:Class ; +. + +:Tag a sh:NodeShape ; + rdfs:label "Tag"@de, "Étiquette"@fr, "Tag"@en ; + sh:targetClass :Tag ; + volipi:iconName "fas fa-tag" ; + sh:property :title, + :description, + :image, + :tag_parent ; +. +:title a sh:PropertyShape ; + rdfs:label "Titel"@de, "Titre"@fr, "Title"@en ; + sh:path :title ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 200 ; +. +:description a sh:PropertyShape ; + rdfs:label "Beschreibung"@de, "Description"@fr, "Description"@en ; + sh:path :description ; + sh:datatype xsd:string ; + sh:maxCount 1 ; +. +:image a sh:PropertyShape ; + rdfs:label "Bild"@de, "Image"@fr, "Image"@en ; + sh:path :image ; + sh:datatype xsd:anyURI ; + sh:maxCount 1 ; +. +:tag_parent a sh:PropertyShape ; + rdfs:label "Übergeordnetes Element"@de, "Élément parent"@fr, "Parent element"@en ; + sh:path :parent ; + sh:class :Tag ; + sh:maxCount 1 ; +. +:Occupation a sh:NodeShape ; + rdfs:label "Beruf"@de, "Profession"@fr, "Occupation"@en ; + sh:targetClass :Occupation ; + volipi:iconName "fas fa-briefcase" ; + sh:property :title, + :description, + :occupation_parent ; +. +:title a sh:PropertyShape ; + rdfs:label "Titel"@de, "Titre"@fr, "Title"@en ; + sh:path :title ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 200 ; +. +:description a sh:PropertyShape ; + rdfs:label "Beschreibung"@de, "Description"@fr, "Description"@en ; + sh:path :description ; + sh:datatype xsd:string ; + sh:maxCount 1 ; +. +:occupation_parent a sh:PropertyShape ; + rdfs:label "Übergeordnetes Element"@de, "Élément parent"@fr, "Parent element"@en ; + sh:path :parent ; + sh:class :Occupation ; + sh:maxCount 1 ; +. +:SeriesType a sh:NodeShape ; + rdfs:label "Serientyp"@de, "Type de série"@fr, "Series type"@en ; + sh:targetClass :SeriesType ; + volipi:iconName "fas fa-list-ol" ; + sh:property :title, + :description ; +. +:title a sh:PropertyShape ; + rdfs:label "Titel"@de, "Titre"@fr, "Title"@en ; + sh:path :title ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 200 ; +. +:description a sh:PropertyShape ; + rdfs:label "Beschreibung"@de, "Description"@fr, "Description"@en ; + sh:path :description ; + sh:datatype xsd:string ; + sh:maxCount 1 ; +. +:ExhibitionSeries a sh:NodeShape ; + rdfs:label "Ausstellungsserie"@de, "Série d'expositions"@fr, "Exhibition series"@en ; + sh:targetClass :ExhibitionSeries ; + volipi:iconName "fas fa-film" ; + sh:property :title, + :description, + :exhibitionSeries_parent, + :seriesType, + :timeSeries, + :location, + :tags ; +. +:title a sh:PropertyShape ; + rdfs:label "Titel"@de, "Titre"@fr, "Title"@en ; + sh:path :title ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 200 ; +. +:description a sh:PropertyShape ; + rdfs:label "Beschreibung"@de, "Description"@fr, "Description"@en ; + sh:path :description ; + sh:datatype xsd:string ; + sh:maxCount 1 ; +. +:exhibitionSeries_parent a sh:PropertyShape ; + rdfs:label "Übergeordnetes Element"@de, "Élément parent"@fr, "Parent element"@en ; + sh:path :parent ; + sh:class :ExhibitionSeries ; + sh:maxCount 1 ; +. +:seriesType a sh:PropertyShape ; + rdfs:label "Serientyp"@de, "Type de série"@fr, "Series type"@en ; + sh:path :seriesType ; + sh:class :SeriesType ; + sh:maxCount 1 ; +. +:timeSeries a sh:PropertyShape ; + rdfs:label "Zeitreihe"@de, "Série chronologique"@fr, "Time series"@en ; + sh:path :timeSeries ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 200 ; +. +:tags a sh:PropertyShape ; + rdfs:label "Tags"@de, "Étiquettes"@fr, "Tags"@en ; + sh:path :tags ; + sh:class :Tag ; + sparna:datasource this:searchWithinTitle_datasource; +. +:Person a sh:NodeShape ; + rdfs:label "Person"@de, "Personne"@fr, "Person"@en ; + sh:targetClass :Person ; + volipi:iconName "fas fa-user" ; + sh:property :name, + :description, + :birthDate, + :deathDate, + :profession, + :nameVariant, + :gender, + :personDeceased, + :externalId, + :workplace, + :memberOfCorp, + :image ; +. +:name a sh:PropertyShape ; + rdfs:label "Name"@de, "Nom"@fr, "Name"@en ; + sh:path :name ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 200 ; +. +:description a sh:PropertyShape ; + rdfs:label "Beschreibung"@de, "Description"@fr, "Description"@en ; + sh:path :description ; + sh:datatype xsd:string ; + sh:maxCount 1 ; +. +:birthDate a sh:PropertyShape ; + rdfs:label "Geburtsdatum"@de, "Date de naissance"@fr, "Birth date"@en ; + sh:path :birthDate ; + sh:datatype xsd:integer ; + sh:maxCount 1 ; +. +:deathDate a sh:PropertyShape ; + rdfs:label "Sterbedatum"@de, "Date de décès"@fr, "Death date"@en ; + sh:path :deathDate ; + sh:datatype xsd:integer ; + sh:maxCount 1 ; +. +:profession a sh:PropertyShape ; + rdfs:label "Beruf"@de, "Profession"@fr, "Profession"@en ; + sh:path :profession ; + sh:class :Occupation ; +. +:nameVariant a sh:PropertyShape ; + rdfs:label "Namensvariante"@de, "Variante du nom"@fr, "Name variant"@en ; + sh:path :nameVariant ; + sh:datatype xsd:string ; +. +:gender a sh:PropertyShape ; + rdfs:label "Geschlecht"@de, "Genre"@fr, "Gender"@en ; + sh:path :gender ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 1 ; + sh:in ( "m" "f" "d" "u" ) ; +. +:personDeceased a sh:PropertyShape ; + rdfs:label "Person verstorben"@de, "Personne décédée"@fr, "Person deceased"@en ; + sh:path :personDeceased ; + sh:datatype xsd:boolean ; + sh:maxCount 1 ; +. +:externalId a sh:PropertyShape ; + rdfs:label "Externe ID"@de, "ID externe"@fr, "External ID"@en ; + sh:path :externalId ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 50 ; +. +:workplace a sh:PropertyShape ; + rdfs:label "Arbeitsplatz"@de, "Lieu de travail"@fr, "Workplace"@en ; + sh:path :workplace ; + sh:class :Workplace ; +. +:memberOfCorp a sh:PropertyShape ; + rdfs:label "Mitglied von Körperschaft"@de, "Membre d'une société"@fr, "Member of corporation"@en ; + sh:path :memberOfCorp ; + sh:class :Corporation ; +. +:image a sh:PropertyShape ; + rdfs:label "Bild"@de, "Image"@fr, "Image"@en ; + sh:path :image ; + sh:datatype xsd:anyURI ; + sh:maxCount 1 ; +. +:Workplace a sh:NodeShape ; + rdfs:label "Arbeitsplatz"@de, "Lieu de travail"@fr, "Workplace"@en ; + sh:targetClass :Workplace ; + volipi:iconName "fas fa-building" ; + sh:property :location, + :fromDate, + :toDate ; +. +:location a sh:PropertyShape ; + rdfs:label "Ort"@de, "Lieu"@fr, "Location"@en ; + sh:path :location ; + sh:class :Location ; + sh:maxCount 1 ; + sparna:datasource this:searchWithinTitle_datasource; +. +:fromDate a sh:PropertyShape ; + rdfs:label "Von Datum"@de, "Date de début"@fr, "From date"@en ; + sh:path :fromDate ; + sh:datatype xsd:integer ; + sh:maxCount 1 ; +. +:toDate a sh:PropertyShape ; + rdfs:label "Bis Datum"@de, "Date de fin"@fr, "To date"@en ; + sh:path :toDate ; + sh:datatype xsd:integer ; + sh:maxCount 1 ; +. +:Location a sh:NodeShape ; + rdfs:label "Ort"@de, "Lieu"@fr, "Location"@en ; + sh:targetClass :Location ; + volipi:iconName "fas fa-map-marker-alt" ; + sh:property :title, + :titleVariants, + :description, + :image, + :location_parent ; +. +:title a sh:PropertyShape ; + rdfs:label "Titel"@de, "Titre"@fr, "Title"@en ; + sh:path :title ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 200 ; +. +:titleVariants a sh:PropertyShape ; + rdfs:label "Titelvarianten"@de, "Variantes du titre"@fr, "Title variants"@en ; + sh:path :titleVariants ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 600 ; +. +:description a sh:PropertyShape ; + rdfs:label "Beschreibung"@de, "Description"@fr, "Description"@en ; + sh:path :description ; + sh:datatype xsd:string ; + sh:maxCount 1 ; +. +:image a sh:PropertyShape ; + rdfs:label "Bild"@de, "Image"@fr, "Image"@en ; + sh:path :image ; + sh:datatype xsd:anyURI ; + sh:maxCount 1 ; +. +:location_parent a sh:PropertyShape ; + rdfs:label "Übergeordnetes Element"@de, "Élément parent"@fr, "Parent element"@en ; + sh:path :parent ; + sh:class :Location ; + sh:maxCount 1 ; +. +:PersonRole a sh:NodeShape ; + rdfs:label "Person Rolle"@de, "Rôle de la personne"@fr, "Person role"@en ; + sh:targetClass :PersonRole ; + volipi:iconName "fas fa-user-tag" ; + sh:property :title, + :description ; +. +:title a sh:PropertyShape ; + rdfs:label "Titel"@de, "Titre"@fr, "Title"@en ; + dash:propertyRole dash:LabelRole ; + sh:path :title ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 200 ; +. +:description a sh:PropertyShape ; + rdfs:label "Beschreibung"@de, "Description"@fr, "Description"@en ; + sh:path :description ; + sh:datatype xsd:string ; + sh:maxCount 1 ; +. +:CorporationRole a sh:NodeShape ; + rdfs:label "Körperschaft Rolle"@de, "Rôle de la société"@fr, "Corporation role"@en ; + sh:targetClass :CorporationRole ; + volipi:iconName "fas fa-building-user" ; + sh:property :title, + :description ; +. +:title a sh:PropertyShape ; + rdfs:label "Titel"@de, "Titre"@fr, "Title"@en ; + sh:path :title ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 200 ; +. +:description a sh:PropertyShape ; + rdfs:label "Beschreibung"@de, "Description"@fr, "Description"@en ; + sh:path :description ; + sh:datatype xsd:string ; + sh:maxCount 1 ; +. +:Place a sh:NodeShape ; + rdfs:label "Stätte"@de, "Lieu"@fr, "Place"@en ; + sh:targetClass :Place ; + volipi:iconName "fas fa-landmark" ; + sh:property :title, + :description, + :titleVariants, + :location, + :place_parent, + :image ; +. +:title a sh:PropertyShape ; + rdfs:label "Titel"@de, "Titre"@fr, "Title"@en ; + sh:path :title ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 200 ; +. +:description a sh:PropertyShape ; + rdfs:label "Beschreibung"@de, "Description"@fr, "Description"@en ; + sh:path :description ; + sh:datatype xsd:string ; + sh:maxCount 1 ; +. +:titleVariants a sh:PropertyShape ; + rdfs:label "Titelvarianten"@de, "Variantes du titre"@fr, "Title variants"@en ; + sh:path :titleVariants ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 600 ; +. +:location a sh:PropertyShape ; + rdfs:label "Ort"@de, "Lieu"@fr, "Location"@en ; + sh:path :location ; + sh:class :Location ; + sh:maxCount 1 ; +. +:place_parent a sh:PropertyShape ; + rdfs:label "Übergeordnetes Element"@de, "Élément parent"@fr, "Parent element"@en ; + sh:path :parent ; + sh:class :Place ; + sh:maxCount 1 ; +. +:image a sh:PropertyShape ; + rdfs:label "Bild"@de, "Image"@fr, "Image"@en ; + sh:path :image ; + sh:datatype xsd:anyURI ; + sh:maxCount 1 ; +. +:EventType a sh:NodeShape ; + rdfs:label "Veranstaltungstyp"@de, "Type d'événement"@fr, "Event type"@en ; + sh:targetClass :EventType ; + volipi:iconName "fas fa-calendar-alt" ; + sh:property :title, + :description ; +. +:title a sh:PropertyShape ; + rdfs:label "Titel"@de, "Titre"@fr, "Title"@en ; + sh:path :title ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 200 ; +. +:description a sh:PropertyShape ; + rdfs:label "Beschreibung"@de, "Description"@fr, "Description"@en ; + sh:path :description ; + sh:datatype xsd:string ; + sh:maxCount 1 ; +. +:Corporation a sh:NodeShape ; + rdfs:label "Körperschaft"@de, "Société"@fr, "Corporation"@en ; + sh:targetClass :Corporation ; + volipi:iconName "fas fa-building" ; + sh:property :name, + :description, + :nameVariant, + :corporation_parent, + :location, + :image ; +. +:name a sh:PropertyShape ; + rdfs:label "Name"@de, "Nom"@fr, "Name"@en ; + dash:propertyRole dash:LabelRole ; + sh:path :name ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 200 ; +. +:description a sh:PropertyShape ; + rdfs:label "Beschreibung"@de, "Description"@fr, "Description"@en ; + sh:path :description ; + sh:datatype xsd:string ; + sh:maxCount 1 ; +. +:nameVariant a sh:PropertyShape ; + rdfs:label "Namensvariante"@de, "Variante du nom"@fr, "Name variant"@en ; + sh:path :nameVariant ; + sh:datatype xsd:string ; +. +:corporation_parent a sh:PropertyShape ; + rdfs:label "Übergeordnetes Element"@de, "Élément parent"@fr, "Parent element"@en ; + sh:path :parent ; + sh:class :Corporation ; + sh:maxCount 1 ; +. +:location a sh:PropertyShape ; + rdfs:label "Ort"@de, "Lieu"@fr, "Location"@en ; + sh:path :location ; + sh:class :Location ; + sh:maxCount 1 ; +. +:image a sh:PropertyShape ; + rdfs:label "Bild"@de, "Image"@fr, "Image"@en ; + sh:path :image ; + sh:datatype xsd:anyURI ; + sh:maxCount 1 ; +. +:ResourceType a sh:NodeShape ; + rdfs:label "Ressourcentyp"@de, "Type de ressource"@fr, "Resource type"@en ; + sh:targetClass :ResourceType ; + volipi:iconName "fas fa-cube" ; + sh:property :title, + :description ; +. +:title a sh:PropertyShape ; + rdfs:label "Titel"@de, "Titre"@fr, "Title"@en ; + sh:path :title ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 200 ; +. +:description a sh:PropertyShape ; + rdfs:label "Beschreibung"@de, "Description"@fr, "Description"@en ; + sh:path :description ; + sh:datatype xsd:string ; + sh:maxCount 1 ; +. +:Resource a sh:NodeShape ; + rdfs:label "Ressource"@de, "Ressource"@fr, "Resource"@en ; + sh:targetClass :Resource ; + volipi:iconName "fas fa-file-alt" ; + sh:property :title, + :description, + :ppn, + :doi, + :url, + :ressourceType, + :signature, + :image ; +. +:title a sh:PropertyShape ; + rdfs:label "Titel"@de, "Titre"@fr, "Title"@en ; + sh:path :title ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 200 ; +. +:description a sh:PropertyShape ; + rdfs:label "Beschreibung"@de, "Description"@fr, "Description"@en ; + sh:path :description ; + sh:datatype xsd:string ; + sh:maxCount 1 ; +. +:ppn a sh:PropertyShape ; + rdfs:label "PPN"@de, "PPN"@fr, "PPN"@en ; + sh:path :ppn ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 15 ; +. +:doi a sh:PropertyShape ; + rdfs:label "DOI"@de, "DOI"@fr, "DOI"@en ; + sh:path :doi ; + sh:datatype xsd:string ; + sh:maxCount 1 ; +. +:url a sh:PropertyShape ; + rdfs:label "URL"@de, "URL"@fr, "URL"@en ; + sh:path :url ; + sh:datatype xsd:anyURI ; + sh:maxCount 1 ; +. +:ressourceType a sh:PropertyShape ; + rdfs:label "Ressourcentyp"@de, "Type de ressource"@fr, "Resource type"@en ; + sh:path :ressourceType ; + sh:class :ResourceType ; + sh:maxCount 1 ; +. +:signature a sh:PropertyShape ; + rdfs:label "Signatur"@de, "Signature"@fr, "Signature"@en ; + sh:path :signature ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 200 ; +. +:image a sh:PropertyShape ; + rdfs:label "Bild"@de, "Image"@fr, "Image"@en ; + sh:path :image ; + sh:datatype xsd:anyURI ; + sh:maxCount 1 ; +. +:ExponatsAndPersons a sh:NodeShape ; + rdfs:label "Exponate und Personen"@de, "Exponats et personnes"@fr, "Exponats and persons"@en ; + sh:targetClass :ExponatsAndPersons ; + volipi:iconName "fas fa-user-circle" ; + sh:property :person, + :personRole ; +. +:person a sh:PropertyShape ; + rdfs:label "Person"@de, "Personne"@fr, "Person"@en ; + sh:path :person ; + sh:class :Person ; + sh:maxCount 1 ; +. +:personRole a sh:PropertyShape ; + rdfs:label "Rolle"@de, "Rôle"@fr, "Role"@en ; + sh:path :role ; + sh:class :PersonRole ; + sh:maxCount 1 ; + dash:searchWidget sparco:ListProperty ; +. +:ExponatsAndCorporations a sh:NodeShape ; + rdfs:label "Exponate und Körperschaften"@de, "Exponats et sociétés"@fr, "Exponats and corporations"@en ; + sh:targetClass :ExponatsAndCorporations ; + volipi:iconName "fas fa-building-circle-check" ; + sh:property :corporation, + :corporationRole ; +. +:corporation a sh:PropertyShape ; + rdfs:label "Körperschaft"@de, "Société"@fr, "Corporation"@en ; + sh:path :corporation ; + sh:class :Corporation ; + sh:maxCount 1 ; +. +:corporationRole a sh:PropertyShape ; + rdfs:label "Rolle"@de, "Rôle"@fr, "Role"@en ; + sh:path :role ; + sh:class :CorporationRole ; + sh:maxCount 1 ; + dash:searchWidget sparco:ListProperty ; +. +:ExhibitionExponat a sh:NodeShape ; + rdfs:label "Ausstellungsexponat"@de, "Exponat d'exposition"@fr, "Exhibition exponat"@en ; + sh:targetClass :ExhibitionExponat ; + volipi:iconName "fas fa-palette" ; + sh:property :title, + :titleVariants, + :description, + :externalId, + :startDate, + :endDate, + :url, + :signature, + :exponatGenres, + :relatedPersons, + :relatedCorporations, + :resources ; +. +:title a sh:PropertyShape ; + rdfs:label "Titel"@de, "Titre"@fr, "Title"@en ; + sh:path :title ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 500 ; +. +:titleVariants a sh:PropertyShape ; + rdfs:label "Titelvarianten"@de, "Variantes du titre"@fr, "Title variants"@en ; + sh:path :titleVariants ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 600 ; +. +:description a sh:PropertyShape ; + rdfs:label "Beschreibung"@de, "Description"@fr, "Description"@en ; + sh:path :description ; + sh:datatype xsd:string ; + sh:maxCount 1 ; +. +:externalId a sh:PropertyShape ; + rdfs:label "Externe ID"@de, "ID externe"@fr, "External ID"@en ; + sh:path :externalId ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 200 ; +. +:startDate a sh:PropertyShape ; + rdfs:label "Startdatum"@de, "Date de début"@fr, "Start date"@en ; + sh:path :startDate ; + sh:node :startDate_NodeShape ; + sh:maxCount 1 ; +. +:startDate_NodeShape a sh:NodeShape ; + rdfs:label "Startdatum Node Shape"@de, "Startdatum Node Shape"@fr, "Start date Node Shape"@en ; + sh:property :startDate_dateValue, + :startDate_dateModifier ; +. +:startDate_dateValue a sh:PropertyShape ; + rdfs:label "Startdatum - Datumswert"@de, "Date de début - Valeur de la date"@fr, "Start date - Date value"@en ; + sh:path :dateValue ; + sh:datatype xsd:integer ; + sh:maxCount 1 ; + sh:maxLength 8 ; +. +:startDate_dateModifier a sh:PropertyShape ; + rdfs:label "Startdatum - Datum Modifikator"@de, "Date de début - Modificateur de date"@fr, "Start date - Date modifier"@en ; + sh:path :dateModifier ; + sh:datatype xsd:integer ; + sh:maxCount 1 ; + sh:in ( 0 1 2 3 ) ; +. +:endDate a sh:PropertyShape ; + rdfs:label "Enddatum"@de, "Date de fin"@fr, "End date"@en ; + sh:path :endDate ; + sh:node :endDate_NodeShape ; + sh:maxCount 1 ; +. +:endDate_NodeShape a sh:NodeShape ; + rdfs:label "Enddatum Node Shape"@de, "Date de fin Node Shape"@fr, "End date Node Shape"@en ; + sh:property :endDate_dateValue, + :endDate_dateModifier ; +. +:endDate_dateValue a sh:PropertyShape ; + rdfs:label "Enddatum - Datumswert"@de, "Date de fin - Valeur de la date"@fr, "End date - Date value"@en ; + sh:path :dateValue ; + sh:datatype xsd:integer ; + sh:maxCount 1 ; + sh:maxLength 8 ; +. +:endDate_dateModifier a sh:PropertyShape ; + rdfs:label "Enddatum - Datum Modifikator"@de, "Date de fin - Modificateur de date"@fr, "End date - Date modifier"@en ; + sh:path :dateModifier ; + sh:datatype xsd:integer ; + sh:maxCount 1 ; + sh:in ( 0 1 2 3 ) ; +. +:url a sh:PropertyShape ; + rdfs:label "URL"@de, "URL"@fr, "URL"@en ; + sh:path :url ; + sh:datatype xsd:anyURI ; + sh:maxCount 1 ; +. +:signature a sh:PropertyShape ; + rdfs:label "Signatur"@de, "Signature"@fr, "Signature"@en ; + sh:path :signature ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 200 ; +. +:exponatGenres a sh:PropertyShape ; + rdfs:label "Exponat Genres"@de, "Genres d'exponats"@fr, "Exponat genres"@en ; + sh:path :exponatGenres ; + sh:class :Genre ; + +. +:relatedPersons a sh:PropertyShape ; + rdfs:label "Verwandte Personen"@de, "Personnes liées"@fr, "Related persons"@en ; + sh:path :relatedPersons ; + sh:class :ExponatsAndPersons ; +. +:relatedCorporations a sh:PropertyShape ; + rdfs:label "Verwandte Körperschaften"@de, "Sociétés liées"@fr, "Related corporations"@en ; + sh:path :relatedCorporations ; + sh:class :ExponatsAndCorporations ; +. +:resources a sh:PropertyShape ; + rdfs:label "Ressourcen"@de, "Ressources"@fr, "Resources"@en ; + sh:path :resources ; + sh:class :Resource ; +. +:ExhibitionCategory a sh:NodeShape ; + rdfs:label "Ausstellungskategorie"@de, "Catégorie d'exposition"@fr, "Exhibition category"@en ; + sh:targetClass :ExhibitionCategory ; + volipi:iconName "fas fa-folder" ; + sh:property :name, + :description ; +. +:name a sh:PropertyShape ; + rdfs:label "Name"@de, "Nom"@fr, "Name"@en ; + sh:path :name ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 200 ; +. +:description a sh:PropertyShape ; + rdfs:label "Beschreibung"@de, "Description"@fr, "Description"@en ; + sh:path :description ; + sh:datatype xsd:string ; + sh:maxCount 1 ; +. +:InvolvedPerson a sh:NodeShape ; + rdfs:label "Beteiligte Person"@de, "Personne impliquée"@fr, "Involved person"@en ; + sh:targetClass :InvolvedPerson ; + volipi:iconName "fas fa-user-check" ; + sh:property :person, + :personRole ; +. +:person a sh:PropertyShape ; + rdfs:label "Person"@de, "Personne"@fr, "Person"@en ; + sh:path :person ; + sh:class :Person ; + sh:maxCount 1 ; + sh:minCount 1 ; + sparna:datasource this:searchName_datasource; +. +:InvolvedCorporation a sh:NodeShape ; + rdfs:label "Beteiligte Körperschaft"@de, "Société impliquée"@fr, "Involved corporation"@en ; + sh:targetClass :InvolvedCorporation ; + volipi:iconName "fas fa-building-flag" ; + sh:property :corporation, + :corporationRole ; +. +:corporation a sh:PropertyShape ; + rdfs:label "Körperschaft"@de, "Société"@fr, "Corporation"@en ; + sh:path :corporation ; + sh:class :Corporation ; + sh:maxCount 1 ; + sh:minCount 1 ; +. +:Genre a sh:NodeShape ; + rdfs:label "Genre"@de, "Genre"@fr, "Genre"@en ; + sh:targetClass :Genre ; + volipi:iconName "fas fa-theater-masks" ; + sh:property :title, + :description, + :image ; +. +:title a sh:PropertyShape ; + rdfs:label "Titel"@de, "Titre"@fr, "Title"@en ; + sh:path :title ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 200 ; +. +:description a sh:PropertyShape ; + rdfs:label "Beschreibung"@de, "Description"@fr, "Description"@en ; + sh:path :description ; + sh:datatype xsd:string ; + sh:maxCount 1 ; +. +:image a sh:PropertyShape ; + rdfs:label "Bild"@de, "Image"@fr, "Image"@en ; + sh:path :image ; + sh:datatype xsd:anyURI ; + sh:maxCount 1 ; +. +:Exhibition a sh:NodeShape ; + rdfs:label "Ausstellung"@de, "Exposition"@fr, "Exhibition"@en ; + sh:targetClass :Exhibition ; + volipi:iconName "fas fa-museum" ; + sh:property :title, + :description, + :startDate, + :endDate, + :subtitle, + :originalTitle, + :exhibitionSeries, + :exhibitionCategory, + :exhibitionGenre, + :exhibition_parent, + :externalId, + :exhibitionType, + :published, + :editorNote, + :placesUnknown, + :places, + :locations, + :tags, + :exposedArtists, + :curators, + :involvedPersons, + :organizers, + :involvedCorporations, + :exhibitionweblink, + :finissage, + :midissage, + :vernissage, + :exponats, + :catalogs, + :resources, + :image ; +. +:title a sh:PropertyShape ; + sh:path :title ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 200 ; +. +:description a sh:PropertyShape ; + sh:path :description ; + sh:datatype xsd:string ; + sh:maxCount 1 ; +. +:startDate a sh:PropertyShape ; + sh:path :startDate ; + sh:node :startDate_NodeShape ; + sh:maxCount 1 ; +. +:startDate_NodeShape a sh:NodeShape ; + sh:property :startDate_dateValue, + :startDate_dateModifier ; +. +:startDate_dateValue a sh:PropertyShape ; + sh:path :dateValue ; + sh:datatype xsd:integer ; + sh:maxCount 1 ; + sh:maxLength 8 ; +. +:startDate_dateModifier a sh:PropertyShape ; + sh:path :dateModifier ; + sh:datatype xsd:integer ; + sh:maxCount 1 ; + sh:in ( 0 1 2 3 ) ; +. +:endDate a sh:PropertyShape ; + sh:path :endDate ; + sh:node :endDate_NodeShape ; + sh:maxCount 1 ; +. +:endDate_NodeShape a sh:NodeShape ; + sh:property :endDate_dateValue, + :endDate_dateModifier ; +. +:endDate_dateValue a sh:PropertyShape ; + sh:path :dateValue ; + sh:datatype xsd:integer ; + sh:maxCount 1 ; + sh:maxLength 8 ; +. +:endDate_dateModifier a sh:PropertyShape ; + sh:path :dateModifier ; + sh:datatype xsd:integer ; + sh:maxCount 1 ; + sh:in ( 0 1 2 3 ) ; +. +:subtitle a sh:PropertyShape ; + sh:path :subtitle ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 200 ; +. +:originalTitle a sh:PropertyShape ; + sh:path :originalTitle ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 200 ; +. +:exhibitionSeries a sh:PropertyShape ; + sh:path :exhibitionSeries ; + sh:class :ExhibitionSeries ; + sh:maxCount 1 ; +. +:exhibitionCategory a sh:PropertyShape ; + sh:path :exhibitionCategory ; + sh:class :ExhibitionCategory ; + sh:maxCount 1 ; +. +:exhibitionGenre a sh:PropertyShape ; + sh:path :exhibitionGenre ; + sh:class :Genre ; + dash:searchWidget sparco:ListProperty ; +. +:exhibition_parent a sh:PropertyShape ; + sh:path :parent ; + sh:class :Exhibition ; + sh:maxCount 1 ; +. +:externalId a sh:PropertyShape ; + sh:path :externalId ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 50 ; +. +:exhibitionType a sh:PropertyShape ; + sh:path :exhibitionType ; + sh:class :EventType ; + sh:maxCount 1 ; + sparna:datasource this:searchStartTitle_datasource; +. + +this:searchStartTitle_datasource a sparna:SparqlDatasource ; + sparna:queryTemplate sparna:query_search_label_strstarts; + sparna:labelProperty :title . + +this:searchWithinTitle_datasource a sparna:SparqlDatasource ; + sparna:queryTemplate sparna:query_search_label_contains; + sparna:labelProperty :title . + +this:searchName_datasource a sparna:SparqlDatasource ; + sparna:queryTemplate sparna:query_search_label_contains; + sparna:labelProperty :name . + +this:searchName_datasource a sparna:SparqlDatasource ; + sparna:queryTemplate sparna:query_search_label_contains; + sparna:labelProperty :name . + +this:search_involvedPerson_datasource a sparna:SparqlDatasource ; + sparna:queryTemplate sparna:query_search_label_contains; + sparna:labelPath "(/)" . +:published a sh:PropertyShape ; + sh:path :published ; + sh:datatype xsd:boolean ; + sh:maxCount 1 ; +. +:editorNote a sh:PropertyShape ; + sh:path :editorNote ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:maxLength 300 ; +. +:placesUnknown a sh:PropertyShape ; + sh:path :placesUnknown ; + sh:datatype xsd:boolean ; + sh:maxCount 1 ; +. +:places a sh:PropertyShape ; + rdfs:label "Stätten"@de, "Lieux"@fr, "Places"@en ; + sh:path :places ; + sh:class :Place ; +. +:locations a sh:PropertyShape ; + rdfs:label "Orte"@de, "Lieux"@fr, "Locations"@en ; + sh:path :locations ; + sh:class :Location ; +. +:exposedArtists a sh:PropertyShape ; + rdfs:label "Ausgestellte Künstler"@de, "Artistes exposés"@fr, "Exposed artists"@en ; + sh:path :exposedArtists ; + sh:class :Person ; +. +:curators a sh:PropertyShape ; + rdfs:label "kuratiert von"@de, "curated by"@en, "curaté par"@fr ; + sh:path :curators ; + sh:class :Person ; + sparna:datasource this:searchName_datasource; +. +:involvedPersons a sh:PropertyShape ; + rdfs:label "Beteiligte Personen"@de, "Personnes impliquées"@fr, "Involved persons"@en ; + sh:path :involvedPersons ; + sh:class :InvolvedPerson ; + dash:searchWidget sparco:NonSelectableProperty ; +. +:organizers a sh:PropertyShape ; + rdfs:label "Organisatoren"@de, "Organisateurs"@fr, "Organizers"@en ; + sh:path :organizers ; + sh:class :Corporation ; + sparna:datasource this:searchName_datasource; +. +:involvedCorporations a sh:PropertyShape ; + rdfs:label "Beteiligte Körperschaften"@de, "Sociétés impliquées"@fr, "Involved corporations"@en ; + sh:path :involvedCorporations ; + sh:class :InvolvedCorporation ; + dash:searchWidget sparco:NonSelectableProperty ; +. +:exhibitionweblink a sh:PropertyShape ; + sh:path :exhibitionweblink ; + sh:datatype xsd:anyURI ; + sh:maxCount 1 ; +. +:finissage a sh:PropertyShape ; + sh:path :finissage ; + sh:node :finissage_NodeShape ; + sh:maxCount 1 ; +. +:finissage_NodeShape a sh:NodeShape ; + sh:property :finissage_dateValue ; +. +:finissage_dateValue a sh:PropertyShape ; + sh:path :dateValue ; + sh:datatype xsd:integer ; + sh:maxCount 1 ; + sh:maxLength 8 ; +. +:midissage a sh:PropertyShape ; + sh:path :midissage ; + sh:node :midissage_NodeShape ; + sh:maxCount 1 ; +. +:midissage_NodeShape a sh:NodeShape ; + sh:property :midissage_dateValue ; +. +:midissage_dateValue a sh:PropertyShape ; + sh:path :dateValue ; + sh:datatype xsd:integer ; + sh:maxCount 1 ; + sh:maxLength 8 ; +. +:vernissage a sh:PropertyShape ; + sh:path :vernissage ; + sh:node :vernissage_NodeShape ; + sh:maxCount 1 ; +. +:vernissage_NodeShape a sh:NodeShape ; + sh:property :vernissage_dateValue ; +. +:vernissage_dateValue a sh:PropertyShape ; + sh:path :dateValue ; + sh:datatype xsd:integer ; + sh:maxCount 1 ; + sh:maxLength 8 ; +. +:exponats a sh:PropertyShape ; + rdfs:label "Exponate"@de, "Exponats"@fr, "Exponats"@en ; + sh:path :exponats ; + sh:class :ExhibitionExponat ; +. +:catalogs a sh:PropertyShape ; + rdfs:label "Ausstellungskataloge"@de, "Catalogues d'exposition"@fr, "Exhibition catalogs"@en ; + sh:path :catalogs ; + sh:class :Resource ; +. +:resources a sh:PropertyShape ; + rdfs:label "Ressourcen"@de, "Ressources"@fr, "Resources"@en ; + sh:path :resources ; + sh:class :Resource ; +. +:image a sh:PropertyShape ; + rdfs:label "Bild"@de, "Image"@fr, "Image"@en ; + sh:path :image ; + sh:datatype xsd:anyURI ; + sh:maxCount 1 ; +. diff --git a/apps/exhibition-live/stories/Architecture.mdx b/apps/exhibition-live/stories/Architecture.mdx new file mode 100644 index 00000000..bf043b81 --- /dev/null +++ b/apps/exhibition-live/stories/Architecture.mdx @@ -0,0 +1,308 @@ +import { Meta } from "@storybook/blocks"; + + + +# The frameworks architecture + + +## The basic configuration + +The configuration can be split into three main parts that are configurable independently: + +1. The data model and its view specific declarations +2. The storage layer +3. The Linked Data Mapping and Prefixing + + +The third part of the configuration will be used by the storage layer and is responsible +to guarantee, that the data produced can always be represented as RDF, no matter which storage +strategy is being used. + +Let's dive into it and examine the specific configuration for a simplified exhibition database. + + +### The data model + +In order to maintain a good structure the current data model lives in its own NPM package within the monorepo. +This allows us to easily share the data model between different parts of the application and amongst CLI, API +and the UI. + +It is located within the `@slub/exhibition-schema` packages located within the `manifestation` directory. + +Even though it could be a simple JSON File it is a TypeScript file to allow for better type checking and +help with the development process. By using the `JSONSchema7` from the `json-schema` package, we'll get code assistance +and validity checking. It won't compile if there is an error and schema is not compliant with the JSON Schema 7 standard. + +```typescript +import { JSONSchema7 } from "json-schema"; + +export const schema: JSONSchema7 = { + $schema: "http://json-schema.org/draft-07/schema#", + $id: "https://schema.adb.arthistoricum.net/exhibition", + $defs: { + Tag: { + type: "object", + properties: { + title: { + type: "string", + maxLength: 200, + }, + description: { + type: "string", + }, + image: { + type: "string", + format: "uri", + }, + parent: { + title: "Übergeordnetes Schlagwort", + $ref: "#/$defs/Tag", + }, + }, + }, + Exhibition: { + type: "object", + properties: { + title: { + type: "string", + maxLength: 200, + }, + tags: { + type: "array", + items: { + $ref: "#/$defs/Tag", + }, + }, + }, + } + } +}; +``` + +Here we see a simple example of a schema that defines an `Exhibition` and a `Tag`. The `Tag` can have a parent tag +and an image. The `Exhibition` can have a title and an array of tags. + +The convention within the Ereignis-Framework is that each entity defined in `definitions` or `$defs` (both are valid +according to the JSON Schema 7 standard) is a separate entity that can be stored in the database. + +Internally the schema will be enhanced with additional properties making it valid JSONLD. As a schema implementer you +don't have to worry about this, as the framework will take care of it. If you want to know more about its internals +read on in at [that chapter](#jsonld-enhancement-and-schema-stubbing). + +### JSONLD enhancement and schema stubbing + +Some parts of the framework use a transformed version of your schema, to add additional properties that are necessary +or should be added implicitly, without the need to incorporate it within the schema in the first place. + +In the `@slub/edb-state-hooks` package you will find a hook called `useExtendedSchema`. It will look into the current +global app context and return a schema, that is stubbed and enhanced with the necessary properties. + +after calling `const schema = useExtendedSchema({ typeName: 'Exhibition' });` you will get a schema that looks like this: + +```json +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://schema.adb.arthistoricum.net/exhibition", + "$defs": { + "TagStub": { + "type": "object", + "properties": { + "title": { + "type": "string", + "maxLength": 200 + }, + "description": { + "type": "string" + }, + "image": { + "type": "string", + "format": "uri" + }, + "@type": { + "const": "http://ontologies.slub-dresden.de/exhibition#Tag", + "type": "string" + }, + "@id": { + "title": "http://ontologies.slub-dresden.de/exhibition/entity/", + "type": "string" + }, + }, + "required": [ + "@type", + "@id" + ] + }, + "ExhibitionStub": { + "type": "object", + "properties": { + "title": { + "type": "string", + "maxLength": 200 + }, + "@type": { + "const": "http://ontologies.slub-dresden.de/exhibition#Exhibition", + "type": "string" + }, + "@id": { + "title": "http://ontologies.slub-dresden.de/exhibition/entity/", + "type": "string" + } + }, + "required": [ + "@type", + "@id" + ] + }, + "Tag": { + "type": "object", + "properties": { + "title": { + "type": "string", + "maxLength": 200 + }, + "description": { + "type": "string" + }, + "image": { + "type": "string", + "format": "uri" + }, + "parent": { + "title": "Übergeordnetes Schlagwort", + "$ref": "#/$defs/TagStub" + }, + "@type": { + "const": "http://ontologies.slub-dresden.de/exhibition#Tag", + "type": "string" + }, + "@id": { + "title": "http://ontologies.slub-dresden.de/exhibition/entity/", + "type": "string" + } + }, + "required": [ + "@type", + "@id" + ] + }, + "Exhibition": { + "type": "object", + "properties": { + "title": { + "type": "string", + "maxLength": 200 + }, + "tags": { + "type": "array", + "items": { + "$ref": "#/$defs/TagStub" + } + }, + "@type": { + "const": "http://ontologies.slub-dresden.de/exhibition#Exhibition", + "type": "string" + }, + "@id": { + "title": "http://ontologies.slub-dresden.de/exhibition/entity/", + "type": "string" + } + }, + "required": [ + "@type", + "@id" + ] + } + }, + "type": "object", + "properties": { + "title": { + "type": "string", + "maxLength": 200 + }, + "tags": { + "type": "array", + "items": { + "$ref": "#/$defs/TagStub" + } + }, + "@type": { + "const": "http://ontologies.slub-dresden.de/exhibition#Exhibition", + "type": "string" + }, + "@id": { + "title": "http://ontologies.slub-dresden.de/exhibition/entity/", + "type": "string" + } + }, + "required": [ + "@type", + "@id" + ] +} +``` + +Quite a bit more than the original. What has happened here? + +First of all, all entities have been extended with a `@type` and `@id` property. The `@type` property is a constant +that will be the same for each instance of a certain type. The `@id` property is a string that will be used to identify +the entity within the graph. If you are not familiar with JSONLD you can read more about it in the [JSONLD specification](https://json-ld.org/) +or learn within the [JSONLD Playground](https://json-ld.org/playground/). + +Second every entity type has a "partner" definition, suffixed with `Stub`. This is a stubbed version of the entity that +has no linked data property. This will be used within the storage layer if we want to make sure only the toplevel entity +gets fetched or stored, without any linked items. + +Lastly, the definition of the type `Exhibition` has been added to the top level of the schema. That will tell the methods using +the schema, that this is the top level entity and should be used as the main entity type, we are referring to. + +When loading the form for a `Tag` the `Tag`-definition will be at the top level, when loading the form for an `Exhibition` +the `Exhibition`-definition will be at the top level and so on. + +Other implicit properties can be added to the schema by configuring the AdbContext. Looking at the `exhibitionAdbConfig` we +see that a function called `makeStubSchema` is being passed to the `AdbContext`. This function will be called with the +`useExtendedSchema` hook instead of the default one if provided. It uses the `prepareStubbedSchema` from `@slub/json-schema-utils` +and adds in addition to the already covered `@type` and `@id` properties, the `idAuthority` property, which is being used +for this specific database as link to other norm databases a bit like the common `sameAs` property in RDF. + +```typescript +import {prepareStubbedSchema} from "@slub/json-schema-utils"; +import {JSONSchema7} from "json-schema"; + +export const makeStubSchema = ( + schema: JSONSchema7 +) => { + return prepareStubbedSchema( + schema, + (modelName: string) => ({ + "@type": { + const: `http://ontologies.slub-dresden.de/exhibition#${modelName.replace(/Stub$/, "")}`, + type: "string", + }, + "@id": { + type: "string", + }, + idAuthority: { + title: "Autorität", + type: "object", + properties: { + "@id": { + title: "IRI", + type: "string", + }, + }, + }, + }), + (_modelName: string) => ["@type", "@id"], + { + excludeType: ["InvolvedPerson", "InvolvedCorporation", "AuthorityEntry"], + excludeSemanticPropertiesForType: ["AuthorityEntry"], + }); +}; +``` + +Within the example provided you can also see, that certain types and properties can be excluded, that does only mean, that no stub schema +will be created for these types or properties. + + + + diff --git a/apps/exhibition-live/stories/Development.mdx b/apps/exhibition-live/stories/Development.mdx new file mode 100644 index 00000000..f75363b4 --- /dev/null +++ b/apps/exhibition-live/stories/Development.mdx @@ -0,0 +1,85 @@ +import { Meta } from "@storybook/blocks"; + + + +# Development Workflows + +## Monorepo + +The EDB Framework follows the software-development-strategy of a [Monorepo](https://en.wikipedia.org/wiki/Monorepo). This means that all the code for the EDB Framework is stored in a single repository, +along with concrete applications and example projects. + +Within the root of the project you will find the following directories: + +- `packages` - Contains all the packages that make up the EDB Framework, including frontend-components, backend-services, and shared libraries. +- `apps` - Contains concrete applications that use the EDB Framework, including the EDB Cli (Console tools for managing EDB projects), and the EDB Web App for exhibitions. +- `manifestations` - Contains data models and declaration files for concrete EDB instances + +By using `turbo` we make sure that every package can be built and tested in isolation, while still being able to reference other packages in the monorepo +and build-pipelines know the internal dependency graph of all packages, thus ensuring that changes to one package are propagated to all dependent packages. + +To build all packages in the monorepo, run the following command: + +```bash +bun run build:packages +``` +which is an alias for `turbo run build --filter=@slub/* --continue`, which will build all packages in the monorepo +within the `@slub` namespace. It will build all packages in parallel, and continue building even if some packages fail. + +## Apps + +The `apps` directory contains concrete applications that use the EDB Framework. These applications are built using dependencies, from the +workspace within the `packages` and `manifestations` directory. + + + +## Versioning + +Versioning is done using `changesets`. Changesets should only be generated when publishing new releases of the EDB Framework. To generate a new changeset, run the following command: + +```bash +# Add a new changeset +changeset + +# Create new versions of packages +changeset version + +# Publish all changed packages to npm +changeset publish +``` + +## Local Development + +For development one needs `bun` and `node` installed. To install `bun` run the following command: + +```bash +npm install -g @bun/cli +``` + +Node can be installed from the [official website](https://nodejs.org/en/). + +If you prefer to use `docker` for development, you can use the provided `docker-compose` file to start a development environment. + + +## Creating a new package + +Different environments require different packages, with altering tsup, eslint and package.json configurations. + +To create a new package, that provides functionality to both targets - **server side nodejs and Browser** - run the following command: + +```bash +hygen edb tsup-package +``` +To create a react-js component package, run the following command: + +```bash +hygen edb frontend-package +``` + +## Creating a new Manifestation (Data Model) + +To create a new manifestation, run the following command: + +```bash +hygen edb manifestation +``` diff --git a/apps/exhibition-live/stories/Introduction.stories.mdx b/apps/exhibition-live/stories/Introduction.stories.mdx deleted file mode 100644 index 178f9965..00000000 --- a/apps/exhibition-live/stories/Introduction.stories.mdx +++ /dev/null @@ -1,481 +0,0 @@ -import { Meta } from '@storybook/addon-docs'; - - - - - -# Welcome to the Exhibition Frontend Stories - -## Exhibition Database Components Library - -This documentation outlines the architecture of a semantic-enabled Next.js frontend framework for json schema-based semantic databases. The framework is adaptable for domain-specific knowledge bases, particularly those used in national or academic library metadata projects. - -## Overview - -The framework is designed to facilitate the management and display of complex metadata in an exhibition database context. It integrates various functionalities like data visualization, form management, data mapping, and external API integration, leveraging JSON Schema and SPARQL for semantic data processing. - -### Components Structure - -#### Basic -- `Link.tsx`: A basic link component. -- `useModifiedRouter.ts`: Custom hook for routing. - -#### Config -- `LobidMaping.stories.tsx`, `lobidMappings.ts`, `lobidMappings.test.ts`: Configuration and testing for Lobid API mappings. -- `permissions.ts`: Permissions configuration. -- `primaryFields.ts`: Configuration for primary fields in data schemas. -- `spreadSheetMapping.ts`: Configuration for mapping spreadsheet data. -- `typeIRIToTypeName.ts`: Utility to map type IRIs to type names. - -#### Content -Includes UI components for main content areas, settings, charts, and timelines. -- `charts`: Bar charts and chart configurations. -- `drawer`: UI components for resizable drawers. -- `main`: Dashboard, search components, forms, and lists. -- `settings`: Forms and modals for various settings. -- `visTimelineWrapper`: Wrapper for timeline visualization. - -#### Exhibition -- `prefixes.ts`: Prefix definitions for the exhibition domain. - -#### Form -Contains components and utilities for form management. -- `discover`, `gnd`, `jsonforms`, `k10plus`, `lobid`, `result`, `show`, `uischema`, `wikidata`, `wizard`: Various subcomponents and utilities related to form functionality. - - -TODO: separate into subfolders - -### Forms Subpackage - -The `Forms` subpackage is a comprehensive module within the framework, designed to handle various aspects of form management in the context of semantic data. It provides components, utilities, and configurations for creating, editing, and displaying forms based on JSON Schema and linked data principles. Below is a detailed breakdown of its contents: - -#### DebouncedAutoComplete.tsx -- A component that provides an autocomplete feature with debouncing, useful for fields requiring suggestions from a large dataset. - -#### DeepGraphToJSONShowcase.stories.tsx and DeepGraphToJSONShowcase.tsx -- Storybook stories and the main component for showcasing the conversion of deep graph data structures to JSON format. - -#### Discover -- `DiscoverAutocompleteInput.tsx`: Autocomplete input for discovery features. -- `DiscoverSearchTable.stories.tsx` and `DiscoverSearchTable.tsx`: Components for rendering searchable tables with storybook integration. - -#### EditExhibitionJSONForm.stories.tsx -- Storybook stories for the JSON form used in editing exhibition data. - -#### formConfigs.ts -- Configuration file for various form-related settings. - -#### FormDebuggingTools.tsx -- A utility component for debugging forms during development. - -#### Form.stories.tsx -- Storybook stories for generic form components. - -#### GenericModal.tsx -- A generic modal component used across different forms. - -#### genSlubJSONLDSemanticProperties.ts -- A utility for generating semantic properties in JSON-LD format specific to SLUB (Saxon State and University Library Dresden). - -#### gnd -- Components related to the GND (Integrated Authority File) integration. -- `GNDAutocompleteInput.stories.tsx` and `GNDAutocompleteInput.tsx`: Autocomplete input component for GND data. - -#### jsonforms -- `index.ts`: Entry point for JSON Forms integration. - -#### k10plus -- Components and utilities for integration with the K10plus library network. -- `examples.json`: Example data for the K10plus network. -- `K10PlusSearchTable.tsx`: Component for K10plus data search. -- `mapping-types.ts`, `marc2rdfMappingDeclaration.ts`, `marcxml2rdf.ts`: Utilities for mapping and converting MARC data to RDF format. - -#### lobid -- Components for integrating with the Lobid API. -- Various table and search components specifically for Lobid data. - -#### result -- Components for displaying search results. -- `ClassicResultListItem.tsx` and `ClassicResultListWrapper.tsx`: Standard components for listing search results. - -#### SemanticJsonFormNoOps.stories.tsx and SemanticJsonFormNoOps.tsx -- Storybook stories and the main component for JSON forms without additional operations. - -#### SemanticJsonFormToolbar.tsx -- A toolbar component for semantic JSON forms, providing user interface elements for form operations. - -#### SemanticJsonForm.tsx -- The main component for creating semantic JSON forms. - -#### show -- Components for displaying detailed views of entities. -- `EntityDetailCard.tsx`, `EntityDetailModal.tsx`, `LoadedEntityDetailModal.tsx`: Components for showing detailed information about specific entities. - -#### SimilarityFinder.tsx -- A component designed to find similarities between entities, useful in data linking and matching scenarios. - -#### TextField.tsx -- A standard text field component used in various forms. - -#### uischema -- Contains JSON schema files for various UI components. -- Examples include schemas for corporation roles, events, exhibitions, and other domain-specific entities. - -#### uischemaForType.ts and uischemas.ts -- Utilities for managing and resolving UI schemas. - -#### wikidata -- Components for integration with Wikidata. -- Includes autocomplete inputs, card displays for human and generic 'thing' entities, and storybook stories. - -#### wizard -- `HorizontalNonLinearStepper.tsx`: A wizard-like component for managing multi-step forms. - -This subpackage demonstrates a deep integration of semantic web principles with modern web UI practices. It supports a wide range of functionalities from basic form inputs to complex data discovery and entity relationship management, making it a versatile tool for projects dealing with complex metadata structures like those in library and academic databases. - -#### Google -- Integration with Google services like Drive and OAuth. - -#### GraphQL -- `queries.graphql.ts`: GraphQL queries. -- `useFetchData.ts`: Custom hook to fetch data using GraphQL. - -#### Helper -- `optionallyCreatePortal.tsx`: Helper for creating React portals. - -#### i18n -- Internationalization utilities. - -#### ImportExport -- `ImportPage.tsx`: Page for data import functionality. - -#### Layout -- `main-layout`: Main layout components like headers, footers, navigation, and sidebar. - -#### Lists -- `datagrid`: Components for data grid display. -- Other list-related components. - -#### Mapping -- Components for data mapping configuration. - -#### Provider -- Context providers for forms and Oxigraph. - -#### Renderer -- Custom renderers for various UI components. - -#### State -- State management hooks and utilities. - -#### Theme -- Theme configuration and custom components. - -#### Types -- GraphQL related types. - -#### Utils -Utility functions and components for various functionalities like AI integration, CRUD operations, data discovery, mapping, SPARQL queries, and more. - -### Pages Structure - -- `_app.tsx`: Custom App component. -- `_document.tsx`: Custom Document component. -- `index.tsx`: Homepage. -- `[locale]`: Locale-specific pages for creating, importing, listing, and infinite listing of various types. - -This architecture provides a comprehensive framework for building semantic data-driven applications, particularly suited for library metadata management systems. The modular design allows for flexibility and adaptability to different domains and data schemas. - -### Updated Documentation for `jsonSchemaBasedDeepGraph2JsonDocumentExtractor.ts` - -#### Overview -`jsonSchemaBasedDeepGraph2JsonDocumentExtractor.ts` is a core utility in the framework, designed to transform RDF graph data into structured JSON documents. This transformation is based on a JSON Schema, making it highly adaptable to various data models. The utility implements a recursive algorithm that navigates through RDF data, constructing a comprehensive JSON document which can be directly utilized in front-end components like forms, generic tables, and detail views. - -#### Functionality -- **Recursive Document Construction**: The utility employs a recursive algorithm to traverse RDF graph data. This process is controlled by multiple depth options which can be configured based on predicate type, class type, and a general maximum recursion depth. - -- **Depth Control**: The depth of recursion is customizable, allowing for detailed control over how deep the algorithm should navigate into relationships like parent-child hierarchies. This feature is essential for tailoring the JSON document structure to specific front-end requirements. - -- **Parameter Customization**: Users can set various parameters to control the extraction process, such as specifying different max-depth values for different types of relationships or data classes. This flexibility ensures that the resulting JSON document aligns with the intended use case. - -#### Use Cases -- **Parent-Child Relationships**: Efficiently handles recursive relationships, like parent-child links, within a specified depth, making it ideal for representing hierarchical data structures. - -- **Semantic-Driven Views**: The JSON documents produced are well-suited for semantic-driven views in the front-end. This includes: - - **Forms**: Populating and managing complex forms with nested or related data. - - **Generic Tables**: Displaying data in table formats where relationships and nested information are crucial. - - **Detail Views**: Creating detailed views of specific entities or objects, where comprehensive and nested information is presented. - -#### Integration -- This utility is integral for front-end components that rely on rich, structured data. By providing a JSON Schema, the extractor can tailor the JSON document to fit the exact needs of these components, ensuring a seamless integration of complex RDF data into user-friendly interfaces. - -#### Configuration -- The utility is highly configurable, allowing developers to specify the depth and nature of the data extraction process. This is critical for balancing the need for detailed data and performance considerations. - -#### Example Usage -```typescript -import { jsonSchemaBasedDeepGraph2JsonDocumentExtractor } from 'utils/graph'; - -// Example JSON Schema -const schema: JsonSchema7 = {...}; - -//Load dataset or get it from a SPARQL endpoint -const ds: Dataset = await getDataset(); - -// Configuration for extraction -const config: Partial = { - omitEmptyArrays: true, - omitEmptyObjects: true, - maxRecursionEachRef: 2, - maxRecursion: 3, - skipAtLevel: 3, - doNotRecurseNamedNodes: true, -}; - -const defaultPrefix = 'http://example.com/'; -const entityIRI = 'http://example.com/Entity'; - -const jsonDocument = jsonSchemaBasedDeepGraph2JsonDocumentExtractor( - defaultPrefix, - entityIRI, - ds as Dataset, - schema, - config, - ); -// Use the jsonDocument in various front-end components -``` - -#### Notes -- This utility is intended to bridge the gap between complex RDF data structures and the requirements of semantic web applications. -- Proper configuration of depth parameters are crucial for optimal performance and relevant data extraction. -- interface might change quickly currently as it still in heavy development, will be specified within a separate implementation -- It's recommended to test and iterate the depth settings based on the specific data models and front-end components in use. - -This documentation provides a clear and specific overview of the `jsonSchemaBasedDeepGraph2JsonDocumentExtractor.ts` utility, focusing on its functionality, use cases, and integration into semantic web applications. -? - -### The Comical Yet Crucial Role of `jsonSchemaBasedDeepGraph2JsonDocumentExtractor` - -disclaimer: this is a comical description of the functionality of the `jsonSchemaBasedDeepGraph2JsonDocumentExtractor` crafted with the help of an artificial intelligence tool and may unintentionally contain some humor and slight inaccuracies. - -Imagine you're at a grand buffet of information – a smorgasbord of semantic data from all corners of the knowledge world. You've got delicacies from Wikidata, a side of GND, a helping of Open Street Map, and even some special dishes prepared by various library institutions and MARC-based data catalogues. But here's the catch: all these dishes are served in their unique, sometimes "exotic" formats – spreadsheets, CSVs, SQL databases, XML files... you name it! - -Now, enter the `jsonSchemaBasedDeepGraph2JsonDocumentExtractor`. This helper function is like your ultimate buffet plate, designed to help you sample everything without getting overwhelmed. Think of it as a magical plate that automatically reshapes itself to hold sushi rolls, soup, salad, or a slice of cake, depending on what you're scooping up. - -In the world of semantic data management tools, this function is a lifesaver. It understands that while you, the user, love the variety of data sources available, you don't necessarily want to juggle the complex utensils (read: graph operations) required to enjoy them. Instead, you prefer to have a simple, document-centric way to map your data feast onto your plate. - -Here’s how it humorously yet effectively handles the chaos: - -1. **Assisted Manual Form Data Input**: It's like having a knowledgeable waiter who suggests the best pairing for your data appetizers. Whether it's GND, Wikidata, or something more niche, this function helps you map these rich sources onto your forms, without you needing to understand the intricacies of their preparation. - -2. **Bulk Import from Exotic Formats**: Got a treasure trove of data in a forgotten Excel dungeon or a CSV cave? No problem! The `jsonSchemaBasedDeepGraph2JsonDocumentExtractor` is like an experienced treasure hunter, adept at extracting valuable insights from these ancient relics and translating them into a more palatable format. - -3. **Mapping Models**: The tool acknowledges a universal truth in the data world – the ever-recurring pattern of trying to fit square pegs (one data model) into round holes (another model). It doesn’t just force them to fit; it expertly carves out a square hole or rounds off the peg, making the integration seamless. - -4. **Dealing with Distributed Knowledge Sources**: Like a masterful conductor of an orchestra, it harmonizes the different instruments (data sources) into a symphony (unified data model). It ensures that the violins (wikidata), cellos (GND), and flutes (library catalogs) all play in unison, creating a melodious data experience. - -In summary, the `jsonSchemaBasedDeepGraph2JsonDocumentExtractor` may have a name that's a mouthful, but it's the hero we need in the complex world of semantic data management. It's the bridge between the vast ocean of distributed knowledge sources and the tranquil island of user-friendly data models. A toast to this unsung hero, making the lives of implementers and domain experts a whole lot easier – and more delightful! 🍷🌉📚 - -### Overview of Interface Abstraction for Search, List, and Detail Observation - -The framework provides a layered architecture to abstract interfaces for search, list, full-text search, and entity detail observation. These interfaces are designed to interact with a storage backend, which can be either a SPARQL 1.1 compliant Triple/Quad store or a standardized GraphQL API. The design caters to the specific features and subtle differences of various databases and APIs by introducing SPARQL middlewares and specific implementations. - -### Interface Abstraction Layers - -1. **Generic Interface Layer**: At the highest level, this layer offers generic interfaces for search, list, and entity observation functionalities. These interfaces are agnostic of the underlying storage mechanism, providing a unified API for front-end components. - -2. **Mapping Layer**: This layer maps the requirements of the generic interface to specific storage backend functionalities. It translates high-level operations into queries and requests suitable for the storage backend, taking into account the data schema and query capabilities. - -3. **Storage Backend Layer**: The actual data storage layer, currently supporting: - - **SPARQL 1.1 Compliant Triple/Quad Stores**: For RDF data management, adhering to the SPARQL 1.1 standards. - - **Standardized GraphQL APIs**: For more generalized data access, utilizing GraphQL as an interface. - -4. **SPARQL Middleware/Implementation Layer**: - - Designed to handle the specificities and unique features of different SPARQL backends. - - Each middleware or implementation is tailored to a specific SPARQL-compliant database, addressing its unique query optimization strategies, extensions, or limitations. - - This layer ensures optimal interaction with the database, leveraging its full capabilities while abstracting these complexities from the higher layers. - -### Key Features - -- **Flexibility**: The architecture is designed to be flexible, accommodating various types of data stores and their unique features. - -- **Scalability**: The abstraction layers allow for scalability, as new types of databases or APIs can be integrated by developing corresponding middlewares or mappings. - -- **Optimization**: Specific implementations for each database or API ensure that the framework can optimize queries and operations according to the capabilities of the backend. - -- **Uniformity**: Despite the backend diversity, the generic interface layer provides a consistent API for the front-end, simplifying development and maintenance. - -### Usage Scenarios - -- **Search and Listing**: Enables complex search and listing operations, including full-text search, across diverse data models and storage backends. - -- **Entity Detail Observation**: Facilitates the retrieval and observation of detailed entity information, crucial for applications requiring in-depth data exploration and visualization. - -- **Adaptability to Backend Changes**: Easily adaptable to changes or upgrades in the storage backend, requiring minimal changes in the higher-level interfaces and front-end components. - -### Examples of Storage Backends - -The described framework can integrate with various storage backends, each offering unique features and capabilities. Below are examples of possible storage backends, including the in-memory SPARQL quad store and those utilizing the Solid protocol. - -#### 1. In-Memory SPARQL Quad Store (Web-Worker Based) -- **Description**: An in-memory, web-worker based quad store, compliant with SPARQL 1.1, implemented in Rust and executed as WebAssembly. It operates within the client's browser, enabling decentralized data management. -- **Features**: - - Fast and efficient RDF data handling. - - Suitable for offline usage and decentralized applications. - - Initial data loading at runtime with dynamic expansion capabilities. - - Data synchronization options to various cloud services and version control platforms. - - other options for data persistence: Changeset(s) and Data is downloadable or can be stored within the browsers local storage - -#### 2. Solid Protocol-Based Storage -- **Description**: Solid (Social Linked Data) is an open standard for decentralized data storage and management, proposed by Tim Berners-Lee. It allows users to store their data securely in decentralized data stores called "Pods" (Personal Online Datastores). -- **Features**: - - User-controlled data storage, enabling data sovereignty. - - Data is stored in a federated manner across various Pods. - - Supports WebID for user authentication and access control, ensuring data privacy and security. - - Compatible with RDF and SPARQL, making it suitable for semantic web applications. - - Provides RESTful APIs for data access, manipulation, and interoperability. - -#### 3. Cloud-Based Triple/Quad Stores -- **Description**: Cloud-based services offering SPARQL 1.1 compliant Triple or Quad stores, such as Amazon Neptune, Stardog Cloud, or GraphDB. -- **Features**: - - Scalable and managed RDF storage solutions. - - Support for SPARQL query language for complex querying. - - High availability and reliability. - - Integrated backup and disaster recovery options. - - Suitable for applications requiring robust, scalable, and managed RDF data management. - -#### 4. Local File-Based RDF Stores -- **Description**: RDF data stored in local files, which can be queried using SPARQL. This is a simpler approach but useful for lightweight or prototype applications. -- **Features**: - - Easy to set up and use for small-scale applications. - - No dependency on network connectivity. - - Limited by local storage capacity and lack of advanced query optimizations. - - Suitable for testing, development, or small standalone applications. - -#### 5. Custom SPARQL-Compliant Databases -- **Description**: Custom implementations of SPARQL-compliant databases tailored to specific application needs. -- **Features**: - - Customizable to specific performance, security, or data model requirements. - - Potential for optimization based on specific use cases. - - Requires more development and maintenance efforts compared to off-the-shelf solutions. - -### Conclusion - -The choice of a storage backend depends on several factors, including data sovereignty, scalability, offline capabilities, and specific application requirements. The framework's flexible architecture allows for seamless integration with a variety of storage solutions, from decentralized, user-controlled Pods in Solid to scalable cloud-based RDF stores, catering to a wide range of use cases in modern web applications. - -This layered architecture effectively bridges the gap between the versatile front-end requirements and the complex, varied back-end storage systems. It provides a robust, scalable, and flexible solution for managing and retrieving data in semantic web applications, particularly suited for environments with diverse and evolving data storage needs. - -These Storybook show all isolated components in action and helps during the development process of the Exhibition catalogue frontend. -It is highly recommended to isolate components further to it's own repository to allow it's usage within further catalogue projects. - -Browse all stories now by navigating to them in the sidebar. -View their code in the `stories` directory to learn how they work. - -We want to commit to building UIs with a [**component-driven**](https://componentdriven.org) process starting with atomic components and ending with pages. - -
- TipEdit the Markdown in{' '} - stories/Introduction.stories.mdx -
diff --git a/apps/exhibition-live/stories/architecture/DataStore.mdx b/apps/exhibition-live/stories/architecture/DataStore.mdx new file mode 100644 index 00000000..68f98dd7 --- /dev/null +++ b/apps/exhibition-live/stories/architecture/DataStore.mdx @@ -0,0 +1,146 @@ +import { Meta } from "@storybook/blocks"; +import {SBMermaid} from "../../.storybook/blocks/SBMermaid"; + + + +# Data Stores + +The EDB Framework supports a variety of data stores. An Abstract Datastore is an interface, that provides the +basic CRUD functionality and some list and utility functions. Some data stores work within the client and within +the server, others are only available on the server. + + The interface make the underlying data store to behave like a document store, where highly linked documents can be +retrieved in one go in a single query. The data store, will most likely use the JSON schema to construct its queries or +to create the necessary indexes during the bootstrap phase. + + The reference implementation is using the SPARQL query language to provide a RDF based data store, that can be used +from the client and the server. + +Dependending on the DataStore the overall architecture will look different. A client side approach, that does not require a classical +Backend will look like the following + + ds[/SPARQL-DataStore\\] + end + ds --> id1[(SPARQL-Database \n e.g. Oxigraph, Allegro, QLever )]`}> + +For testing purpose it can even be a local in memory SPARQL Database (driven by a webworker) + + ds[/SPARQL-DataStore \n with local worker config\\] --> id1[(in memory Oxigraph)] + end + id1 -- export/download --> tr[Triples export.ttl or export.json]`}> + + +When using the Restful-DataStore within the client and the SPARQL-DataStore within the Backend the chart will +look like the following: + + ds[/RESTfull-DataStore\\] + end + ds -- REST request --> rh[REST Request Handler] + subgraph Server + rh --> ds2[/SPARQL-DataStore\\] + end + ds2 --> id1[(SPARQL-Database)]`}> + +Another example would be Prisma in combination with Postgres: + + + ds[/RESTfull-DataStore\\] + end + ds -- REST request --> rh[REST Request Handler] + subgraph Server + rh --> ds2[/Prisma-DataStore\\] --> PrismaORM + end + PrismaORM --> id1[(Postgres)]`}> + + +## SPARQL Data Store + +The package `@slub/sparql-db-implementation` provides a SPARQL based data store implementation. The data store is +using SPARQL 1.1 Update, Select and Construct queries to interact with the data store. By using the JSON schema +provided. + +## RESTful Data Store + +The package `@slub/restful-fetch-db-implementation` provides a RESTful based data store implementation. It will store and query +the data via fetch requests. A reference REST API implementation can be found under `./apps/edb-api`. The REST API itself can +use any kind of data store. + +The package `@slub/restful-fetch-db-implementation` + +The API is documented using the OpenAPI 3.0 specification, thus the API can be explored using Swagger UI. + +Within the package `@slub/edb-state-hooks`, this implementation will be used by the hook `useDataStore` if the `provider` of the endpoint-configuration +is set to `rest`. + +A Restful Data Store can be initialized with the following configuration: + +```typescript +import { initRestfullStore } from "@slub/restfull-fetch-db-impl"; +const schema = {...} + +initRestfullStore({ + apiURL: "http://localhost:3001", + defaultPrefix: "http://ontologies.slub-dresden.de/exhibition#", + typeNameToTypeIRI: (typeName: string) => `http://ontologies.slub-dresden.de/exhibition#${typeName}`, + schema, + defaultLimit: 10, + }) +``` + +## Prisma Data Store + + +The package `@slub/prisma-db-implementation` provides a Prisma based data store implementation. It will store and query +the data via Prisma ORM, which itself supports a wide range of databases, like MariaDB, PostgreSQL, SQLite, MongoDB. +For a complete list of supported databases, see [Prisma Database Support](https://www.prisma.io/docs/orm/reference/supported-databases) + +Because Prisma itself uses a schema and needs database migration if the model changes, we loose a little bit of flexibility +compared to the SPARQL Data Store. But we gain a lot of performance and can use the full power of the underlying database. + +### Prisma Data Store Configuration + +By setting the environment variable `DATABASE_URL` to the connection string of the database +and `DATABASE_PROVIDER`, the Prisma Data Store can be initialized . + +Assuming we already creafted our model with JSON schema, we can initialize the Prisma Data Store with the following configuration: + +In the root of the project run: + + ```bash +bun run build:prisma +``` + +This will build the prisma schema, that is being put into the `prisma` folder. +The next step is to generate the prisma client. Prisma uses code generation +to create an optimal client for the database. This can be done by running: + +```bash +bun run prisma:exhibition:generate +``` + +It will install a package called `@prisma/edb-exhibition-client` that can be used within the API +and CLI. But a last step is necessary to initialize the database itself. If the database already exists +it will run migrations on the database to accommodate the schema changes. This can be done by running: + +```bash +bun run prisma:exhibition:migrate +``` + +Once we have initialized the database, we can seed it or import data from another data store using the cli. + +```bash +bun run cli import Exhibition --importFrom oxigraph +``` + +This will import all entities of the type `Exhibition` from the oxigraph data store. +It requires `oxigraph` to be set as import store in the configuration. + + diff --git a/apps/exhibition-live/stories/components/QuerySparnatural.stories.tsx b/apps/exhibition-live/stories/components/QuerySparnatural.stories.tsx new file mode 100644 index 00000000..c1dbb0ea --- /dev/null +++ b/apps/exhibition-live/stories/components/QuerySparnatural.stories.tsx @@ -0,0 +1,16 @@ +import { Meta, StoryObj } from "@storybook/react"; +import { QuerySparnatural } from "./QuerySparnatural"; + +const meta: Meta = { + component: QuerySparnatural, + title: "Components/QuerySparnatural", +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + lang: "en", + }, +}; diff --git a/apps/exhibition-live/stories/components/QuerySparnatural.tsx b/apps/exhibition-live/stories/components/QuerySparnatural.tsx new file mode 100644 index 00000000..c76610a8 --- /dev/null +++ b/apps/exhibition-live/stories/components/QuerySparnatural.tsx @@ -0,0 +1,180 @@ +import { EdbSparnatural } from "@slub/edb-sparnatural"; +import { useAdbContext, useGlobalCRUDOptions } from "@slub/edb-state-hooks"; +import { useCallback, useState } from "react"; +import df from "@rdfjs/data-model"; +import { fixSparqlOrder, withDefaultPrefix } from "@slub/sparql-schema"; +import { SELECT } from "@tpluscode/sparql-builder"; +import { filterUndefOrNull, isValidUrl } from "@slub/edb-core-utils"; +import { + GenericListItem, + GenericVirtualizedList, +} from "@slub/edb-virtualized-components"; +import { IRIToStringFn, PrimaryFieldDeclaration } from "@slub/edb-core-types"; +import get from "lodash/get"; +import debounce from "lodash/debounce"; +import isString from "lodash/isString"; +import * as React from "react"; +import { ParentSize } from "@visx/responsive"; +import NiceModal from "@ebay/nice-modal-react"; +import { Box, Skeleton } from "@mui/material"; + +const itemToListItem = ( + item: any, + typeIRI: string, + typeIRIToTypeName: IRIToStringFn, + primaryFields: PrimaryFieldDeclaration, +): GenericListItem | null => { + const typeName = typeIRIToTypeName(typeIRI); + if (isString(item.entity?.value)) { + const primaryField = primaryFields[typeName]; + const primary = primaryField + ? get(item, primaryField.label)?.value + : JSON.stringify(item); + const description = primaryField + ? get(item, primaryField.description)?.value + : null; + const image = primaryField ? get(item, primaryField.image)?.value : null; + return { + id: item.entity.value, + entry: item, + primary: primary || typeName, + description, + avatar: image, + }; + } + return null; +}; + +type QuerySparnaturalProps = { + lang: "en" | "de" | "fr"; +}; +export const QuerySparnatural = ({ lang }: QuerySparnaturalProps) => { + const { crudOptions } = useGlobalCRUDOptions(); + const { + typeNameToTypeIRI, + typeIRIToTypeName, + jsonLDConfig: { defaultPrefix }, + queryBuildOptions: { primaryFields }, + components: { EntityDetailModal }, + } = useAdbContext(); + const { selectFetch } = crudOptions || {}; + const [data, setData] = useState([]); + const [loading, setLoading] = useState(false); + + const fetchFromEntries = useCallback( + async (entries: { entityIRI: string; typeIRI: string }[]) => { + if (!selectFetch) return []; + const optionalProperties = [ + "title", + "name", + "label", + "description", + "image", + ]; + if (!entries.length) return []; + const sample = (propName: string) => + ` (SAMPLE(?${propName}List) AS ?${propName}) `; + const makeOptional = (propName: string) => + `OPTIONAL { ?entity :${propName} ?${propName}List . }`; + const wherePartOptionals = optionalProperties + .map(makeOptional) + .join("\n"); + const selectPartOptionals = optionalProperties.map(sample).join(" "); + const entityV = df.variable("entity"); + const query = fixSparqlOrder( + withDefaultPrefix( + defaultPrefix, + SELECT.DISTINCT`${entityV} ?type ${selectPartOptionals} `.WHERE` + ${entityV} a ?type . + VALUES ${entityV} { ${entries.map((entry) => `<${entry.entityIRI}>`).join(" ")} } . + FILTER(isIRI(${entityV})) + ${wherePartOptionals} + `.GROUP().BY`${entityV} ?type` + .ORDER() + .BY(entityV) + .build(), + ), + ); + const rawResults = await selectFetch(query); + const result = filterUndefOrNull( + rawResults?.map((item) => + itemToListItem( + item, + item.type.value, + typeIRIToTypeName, + primaryFields, + ), + ) || ([] as GenericListItem[]), + ); + return result; + }, + [typeIRIToTypeName, selectFetch, defaultPrefix, primaryFields], + ); + + const doQuery = useCallback( + async (queryString: string) => { + const response = await selectFetch(queryString); + console.log({ response }); + const entries = response.flatMap((item: any) => { + return filterUndefOrNull( + Object.entries(item).map(([key, value]: [string, any]) => { + if (value.type !== "uri") return null; + const typeName = key.split("_")[0]; + const entityIRI = value.value; + if (!isValidUrl(entityIRI)) return null; + return { typeIRI: typeNameToTypeIRI(typeName), entityIRI }; + }), + ); + }); + const result = await fetchFromEntries(entries); + setData(result); + setLoading(false); + }, + [selectFetch, typeNameToTypeIRI, setData, setLoading], + ); + + const handleQueryUpdate = React.useRef(debounce(doQuery, 500)).current; + const showEntry = useCallback( + (entityIRI: string) => { + NiceModal.show(EntityDetailModal, { + entityIRI, + disableInlineEditing: true, + }); + }, + [EntityDetailModal], + ); + return ( + <> + { + setLoading(true); + handleQueryUpdate(event.detail.queryString); + }} + /> + + {loading ? ( + + ) : ( + + {({ width, height }) => ( + + )} + + )} + + + ); +}; diff --git a/apps/exhibition-live/stories/development/BuildCache.mdx b/apps/exhibition-live/stories/development/BuildCache.mdx new file mode 100644 index 00000000..86085e96 --- /dev/null +++ b/apps/exhibition-live/stories/development/BuildCache.mdx @@ -0,0 +1,30 @@ +## Turbo Cache in Your Project + +Turbo Cache drastically improves build times in monorepo setups by caching the results of previous builds and reusing them when possible. This is particularly beneficial for our project, which combines multiple UI projects (Vite.js, Next.js, Storybook), a Node.js CLI/API, and shared packages. + +### How Turbo Cache Works: + +1. **Task Fingerprinting:** Turbo analyzes each task definition (e.g., build command for Vite.js project) along with its dependencies (files within the Vite.js project, shared packages) and environment variables. It generates a unique hash ("fingerprint") representing this specific task configuration. + +2. **Cache Lookup:** When you run a task, Turbo checks if a cached output exists for the corresponding fingerprint. + +3. **Cache Hit/Miss:** +- **Hit:** If found, Turbo skips the actual execution and uses the cached output, resulting in significantly faster build times. +- **Miss:** If not found (e.g., first-time execution, code changes detected), Turbo executes the task, caches the output, and associates it with the generated fingerprint for future use. + +**Impact on Our Project and Workspace Dependencies:** + +Turbo's understanding of workspace dependencies is crucial for our monorepo's efficiency. Let's illustrate with an example: + +Imagine our Vite.js project depends on a utility function from a shared package located in `packages/utils`. + +1. **Initial Build:** On the first build of both the `utils` package and the Vite.js project, Turbo caches the outputs and associates them with their respective fingerprints. + +2. **Change in Shared Package:** Now, let's say you modify the utility function within `packages/utils`. Turbo's dependency graph detects this change and knows that the Vite.js project relies on the modified package. + +3. **Targeted Rebuilds:** Turbo intelligently invalidates only the cached outputs related to the `utils` package and the Vite.js project. This means: +- The `utils` package is rebuilt. +- The Vite.js project is rebuilt, leveraging the updated output from the rebuilt `utils` package. +- Other unrelated parts of the monorepo remain untouched, preserving their cached states and saving significant build time. + +In essence, Turbo's workspace dependency awareness ensures that only the necessary parts of your monorepo are rebuilt when changes occur, maximizing caching efficiency and streamlining your development process. diff --git a/apps/exhibition-live/stories/development/Packaging.mdx b/apps/exhibition-live/stories/development/Packaging.mdx new file mode 100644 index 00000000..5934dc8c --- /dev/null +++ b/apps/exhibition-live/stories/development/Packaging.mdx @@ -0,0 +1,191 @@ +import { Meta } from "@storybook/blocks"; + + + +# Packaging + +In order to add functionality to either the CLI, the API or the frontend to guarantee maximum code reusage +and a clear separation of dependencies we encourage to create a new package for each new feature. + +## How to write a package + +you can start with a template using the `hygen` generator: + +```bash +hygen edb +``` + +Presents a wizard where you can choose the name of the package and the type of package you want to create. +It will automatically set up the base structure of the package optimized for the distribution you choose. + +A package, without any frontend dependencies like react, can be scaffolded with: + +```bash +hygen edb tsup-package +``` + +### Example + +Let's assume we want to integrate some third party library like [sparnatural](https://sparnatural.eu/) into the frontend. + + +1. Create a new package + +```bash +hygen edb frontend-package +``` + +We will call it `@slub/edb-sparnatural`. This will generate a new package in the `packages` directory. + +2. Examine the package within the Storybook + +After launching the Storybook, you can see the new package in the sidebar. A scaffold component should have been created. +```bash +bun run storybook +``` + +The generated `package.json` should look like that: + +```json +{ + "name": "@slub/edb-sparnatural", + "version": "1.0.0", + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.js", + "require": "./dist/index.cjs", + "default": "./dist/index.js", + "types": "./dist/index.d.ts" + } + }, + "scripts": { + "build": "tsup src/index.tsx", + "dev": "tsup src/index.tsx", + "lint": "eslint \"**/*.ts*\"", + "lint-fix": "eslint --fix \"**/*.ts*\"" + }, + "peerDependencies": { + "@mui/material": "^5", + "@mui/icons-material": "^5", + "react": "^18" + }, + "dependencies": { + }, + "devDependencies": { + "@slub/edb-build-helper": "workspace:*", + "@slub/edb-tsconfig": "workspace:*", + "@slub/edb-tsup-config": "workspace:*" + } +} +``` + +Go to the package directory and install the dependencies: + +We will remove the `@mui/*` dependencies and add the `sparnatural` dependency using bun: + +```bash +bun remove @mui/material @mui/icons-material --peer +bun add sparnatural +``` + +3. Implement the package + +No modify the `src/EdbSparnatural.tsx` file to include the `sparnatural` library. Because Sparnatural is a webcomponent we need to tacle arround not having the component beeing recognized by React. +So a `declarations.d.ts` file is needed to declare the `spar-natural` WebComponent. + +```typescript +namespace JSX { + interface IntrinsicElements { + "spar-natural": SparnaturalAttributes; + } + + interface SparnaturalAttributes { + ref:React.RefObject + src: string; + lang: string; + endpoint: string; + distinct: string; + limit: string; + prefix: string; + debug:string + } +} +``` + +Teh final `src/EdbSparnatural.tsx` file should look like this: + +```tsx +import React, { useEffect, useRef } from 'react'; +import "sparnatural/src/assets/stylesheets/sparnatural.scss"; + +export interface SparnaturalEvent extends Event { + detail?: { + queryString: string, + queryJson: string, + querySparqlJs: string + } +} +export type EdbSparnaturalProps = { + src: string; + lang: string; + endpoint: string; + distinct: string; + limit: string; + prefix: string; + debug: string; +} + +export const EdbSparnatural: React.FC = ({ + src, + lang, + endpoint, + distinct, + limit, + prefix, + debug, +}) => { + const sparnaturalRef = useRef(null); + + useEffect(() => { + import("sparnatural").then(() => { + const handleQueryUpdated = (event: SparnaturalEvent) => { + console.log(event?.detail?.queryString); + console.log(event?.detail?.queryJson); + console.log(event?.detail?.querySparqlJs); + // here : don't forget to call expandSparql so that core:sparqlString annotation is taken into account + }; + + sparnaturalRef.current?.addEventListener("queryUpdated", handleQueryUpdated); + + return () => { + sparnaturalRef.current?.removeEventListener("queryUpdated", handleQueryUpdated); + }; + }); + }, []); + + return ( + + ); +}; +``` + +4. Build the package + +```bash +bun run build +``` diff --git a/apps/exhibition-live/stories/development/ProblemSolving.mdx b/apps/exhibition-live/stories/development/ProblemSolving.mdx new file mode 100644 index 00000000..88576aee --- /dev/null +++ b/apps/exhibition-live/stories/development/ProblemSolving.mdx @@ -0,0 +1,90 @@ +import { Meta } from "@storybook/blocks"; + + + +# Problem Solving + +This package is dedicated to problems that can occur during development and how to solve them. + +## Reinstall all dependencies + +## next.js Development errors + +Sometime dependencies are not compatible with next.js in dev mode and it throws errors like below: + +``` +adb-next:dev: ⨯ ../../node_modules/@jsonforms/material-renderers/node_modules/@mui/icons-material/node_modules/@babel/runtime/helpers/interopRequireDefault.js +adb-next:dev: Module parse failed: Cannot use 'import.meta' outside a module (38:6) +adb-next:dev: File was processed with these loaders: +``` + +First one has to check whether the error does not appear in production mode, by building the project and running it. +If it really just shows up in dev mode and a complete reinstallation of node dependencies does not help, one can try to exclude the problematic module from being transpiled by next.js. +Delete it manually from the `node_modules` folder and add it to the `transpileModules` array in the `next.config.js` file. + + +# NextJS Development Errors + +## Collecting page data .ReferenceError: window is not defined + +This error occurs when a component is trying to access the window object during server side rendering. To fix this, wrap the code that is trying to access the window object in a check to see if the window object is defined. + +This example comes from the `@slub/edb-debug-utils` package: + +```typescript jsx +import dynamic from "next/dynamic"; +import {YasguiSPARQLEditorProps} from "./YasguiSPARQLEditorProps"; + +const DynamicComponentWithNoSSR = dynamic( + () => import("./YasguiSPARQLEditor"), + { + ssr: false, + }, +); + +export const YasguiSPARQLEditorNoSSR = (props: YasguiSPARQLEditorProps) => ( + +); +``` +#### Explanation: + +1. Use separate `.ts` File for Props +2. Use `dynamic` from `next/dynamic` to import the component + +If the error still persists, try to wrap the external library within an dynamic import: + +```typescript jsx +import type Yasgui from "@triply/yasgui"; +import React, {FunctionComponent, useEffect, useState} from "react"; + +import {YasguiSPARQLEditorProps} from "./YasguiSPARQLEditorProps"; + +export const YasguiSPARQLEditor: FunctionComponent = ({ + onInit +}) => { + const [yasgui, setYasgui] = useState(null); + + useEffect(() => { + import("@triply/yasgui").then(({default: YasguiCls}) => { + setYasgui((yg) => { + const el = document.getElementById("yasgui"); + return yg ? yg : new YasguiCls(el, { yasqe: { + queryingDisabled: undefined, + showQueryButton: true }}) + }); + }); + }, [setYasgui]); + + useEffect(() => { + if (yasgui && onInit) onInit(yasgui); + }, [onInit, yasgui]); + + return
; +}; + +``` + +#### Explanation: + +1. For typescript, use `import type` to import the type of the library, this will not import the library itself, but only the type +2. Use `import` to import the library itself within the `useEffect` hook, this will only import the library when the component is rendered diff --git a/apps/exhibition-live/stories/development/Reconcilation.mdx b/apps/exhibition-live/stories/development/Reconcilation.mdx new file mode 100644 index 00000000..54a84204 --- /dev/null +++ b/apps/exhibition-live/stories/development/Reconcilation.mdx @@ -0,0 +1,97 @@ +import { Meta, Markdown } from "@storybook/blocks"; + + + +# Reconcilation + +**Date: 2024-08-01** +**Source: [Thread on Github](https://github.com/reconciliation-api/specs/issues/104#issuecomment-1355364865)** + +For autosuggest and entity linking, we use the Freebase Reconciliation API next to other methods. The Reconciliation API is a service that takes a string as input and returns a list of entity IDs which are likely to be the entity that the string represents. The API can be used to reconcile entities from Freebase or other sources. + +Even though it is not part of the EDB Framework for reference , we'll provide the following information about the Reconciliation API: + +## parameters of the Reconciliation API + + + {` +| Parameter name | Value | Description | +|---------------------|---------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Optional parameters | | | +| as_of_time | string | A MQL as_of_time value to use with mql_output queries. | +| callback | string | JS method name for JSONP callbacks. | +| cursor | integer | The cursor parameter along with the limit parameter allows you to page through a defined number of results at a time. For example, to present 3 pages of successive 10 results, use  limit=10 and cursor=0, then cursor=10, and cursor=20. | +| domain | string | Restrict to topics with this Freebase domain ID. | +| encode | string | The encoding of the response. You can use this parameter to enable HTML encoding.Acceptable values are:"html": Encode certain characters in the response (such as tags and ampersands) using HTML encoding."off": No encoding of the response. You should not print the results directly on a web page without HTML-escaping the content first. (default) | +| exact | boolean | Query on exact name and keys only. | +| filter | string | The filter parameter allows you to create more complex rules and constraints to apply to your query.The filter value is a simple language that supports the following symbols:the all, any, should and not operatorsthe type, domain, name, alias, with and without operandsthe ( and ) parenthesis for grouping and precedenceTo learn how to use the filter property see the Search Cookbook. | +| format | string | Structural format of the JSON response.Acceptable values are:"entity": Basic information about the entities. (default)"ids": Ordered list of Freebase ids."mids": Ordered list of Freebase mids. | +| indent | boolean | Whether to indent the JSON results or not. | +| lang | string | The code of the language with which to run the query. Default is 'en'. | +| limit | integer | Maximum number of results to return. By default, 20 matches in decreasing order of relevance are returned, if that many exist. Fewer or more matches may be requested by using the limit parameter with a different value. (Example.) | +| mql_output | string | The MQL query to run againist the results to extract more data. After the query is run, the matching documents' IDs are passed to the mql_output MQL query to retrieve actual data about the matches. The MQL results are sorted by decreasing relevance score. | +| prefixed | boolean | Prefix match against names and aliases. | +| query | string | Query term to search for. | +| scoring | string | Relevance scoring algorithm to use.Acceptable values are:"entity": Use Freebase and popularity entity ranking. (default)"freebase": Use Freebase entity ranking."schema": Use schema ranking for properties and types. | +| spell | string | Request 'did you mean' suggestionsAcceptable values are:"always": Request spelling suggestions for any query at least three characters long."no_results": Request spelling suggestions if no results were found."no_spelling": Don't request spelling suggestions. (default) | +| stemmed | boolean | Query on stemmed names and aliases. May not be used with prefixed. | +| type | string | Restrict to topics with this Freebase type id. | +| with | string | A filter rule to match against. | +| without | string | A filter rule to not match against. + | + `} + + +All parameters below are optional but you must have one of either [query](https://developers.google.com/freebase/v1/search#query) or [filter](https://developers.google.com/freebase/v1/search#filter). + +### Parameter name Value Description + +#### Optional parameters +- as_of_time string A MQL as_of_time value to use with mql_output queries. +- callback string JS method name for JSONP callbacks. +- cursor integer The cursor parameter along with the limit parameter allows you to page through a defined number of results at a time. For example, to present 3 pages of successive 10 results, use limit=10 and cursor=0, then cursor=10, and cursor=20. +- domain string Restrict to topics with this Freebase domain ID.\ +encode string The encoding of the response. You can use this parameter to enable HTML encoding. + +#### Acceptable values are: +- "html": Encode certain characters in the response (such as tags and ampersands) using HTML encoding.\ +- "off": No encoding of the response. You should not print the results directly on a web page without HTML-escaping the content first. (default)\ +exact boolean Query on exact name and keys only.\ +filter string\ +The filter parameter allows you to create more complex rules and constraints to apply to your query. + +The filter value is a simple language that supports the following symbols: + +the all, any, should and not operators\ +the type, domain, name, alias, with and without operands\ +the ( and ) parenthesis for grouping and precedence\ +To learn how to use the filter property see the [Search Cookbook](https://developers.google.com/freebase/v1/search-cookbook). + +### format string Structural format of the JSON response. + +#### Acceptable values are: +- "entity": Basic information about the entities. (default)\ +- "ids": Ordered list of Freebase ids.\ +- "mids": Ordered list of Freebase mids.\ +indent boolean Whether to indent the JSON results or not.\ +lang string The code of the language with which to run the query. Default is 'en'.\ +limit integer Maximum number of results to return. By default, 20 matches in decreasing order of relevance are returned, if that many exist. Fewer or more matches may be requested by using the limit parameter with a different value. ([Example](https://www.googleapis.com/freebase/v1/search?query=tiger&limit=5&indent=true).)\ +mql_output string The MQL query to run againist the results to extract more data. After the query is run, the matching documents' IDs are passed to the mql_output MQL query to retrieve actual data about the matches. The MQL results are sorted by decreasing relevance score.\ +prefixed boolean Prefix match against names and aliases.\ +query string Query term to search for.\ +scoring string Relevance scoring algorithm to use. + +#### Acceptable values are: +- "entity": Use Freebase and popularity entity ranking. (default)\ +- "freebase": Use Freebase entity ranking.\ +- "schema": Use schema ranking for properties and types.\ +spell string Request 'did you mean' suggestions + +#### Acceptable values are: +- "always": Request spelling suggestions for any query at least three characters long.\ +- "no_results": Request spelling suggestions if no results were found.\ +- "no_spelling": Don't request spelling suggestions. (default)\ +stemmed boolean Query on stemmed names and aliases. May not be used with prefixed.\ +type string Restrict to topics with this Freebase type id.\ +with string A filter rule to match against.\ +without string A filter rule to not match against. diff --git a/apps/exhibition-live/stories/development/SimilarityFinder.mdx b/apps/exhibition-live/stories/development/SimilarityFinder.mdx new file mode 100644 index 00000000..fb78c1d1 --- /dev/null +++ b/apps/exhibition-live/stories/development/SimilarityFinder.mdx @@ -0,0 +1,19 @@ +import {Canvas, Meta} from "@storybook/blocks"; +import * as SimilarityFinderStories from "../../components/form/similarity-finder/SimilarityFinder.stories"; + + + +# Similarity Finder + +When entering new Data into the Form, the user is assisted by the so called "Similarity Finder", which can bee seen +exemplified within the following component story [here](/story/maintenance-norm-data--similarity-finder). For almost +all relations to other entities like persons, companies, resources, etc. the user can search for existing entities +within the own database or within various external sources, where the [GND](https://www.dnb.de/EN/Professionell/Standardisierung/GND/gnd_node.html) +is the most prominent one, within the exhibition database. + + + +## Adding new sources + +The file `useKnowledgeBases.tsx` within the source folder of the `SimilarityFinder` component. It is responsible +for the configuration of all knowledge bases, which are accessible within the Similarity Finder. The configuration diff --git a/apps/exhibition-live/stories/maintenance/Cli.mdx b/apps/exhibition-live/stories/maintenance/Cli.mdx new file mode 100644 index 00000000..76fa5812 --- /dev/null +++ b/apps/exhibition-live/stories/maintenance/Cli.mdx @@ -0,0 +1,60 @@ +import { Meta } from "@storybook/blocks"; +import {SBMermaid} from "../../.storybook/blocks/SBMermaid"; + + + + +# EDB Cli + +The EDB Cli is a command-line tool for accessing and mapping data according to the current EDB data model defined by the JSON Schema. + +The Cli will use the global configuration provided by the environment (for example `.env` file) to connect to the configured DataStore +and what model to use. + +The CLI also supports a list of Import-DataStores, which can be used to import data from other data sources. +The data flow looks as follows (in the example a Prisma DataStore is being used) : + + + + ds2[/Main-DataStore\\] --> PrismaORM + ds3[/Import-DataStore 1\\] -- import --> ds2 + ds4[/Import-DataStore 2\\] -- import --> ds2 + end + CLI -- output --> jsonld[JSON-LD Documents] + PrismaORM --> id1[(Postgres)]`}> + +To run the EDB Cli, run the following command: + +```bash +bun run cli +``` +It will show you the available subcommands and options. + +``` +edb-cli + +where can be one of: + +- list +- get +- flatImport - Import of flat table structured documents +- import - Recursively import data from another data store + +For more help, try running `edb-cli --help` +``` + +#### Retrieving Data + +Use the list or get command to retrieve data from the EDB Cli. The list command will list all documents, while the get command will retrieve a specific data object. + +```bash +bun run cli list Person -n 10 +``` +will list 10 documents of the type `Person`. + +```bash +bun run cli get Person http://ontologies.slub-dresden.de/exhibition/entity#XYZ +``` +will retrieve the document with the id `http://ontologies.slub-dresden.de/exhibition/entity#XYZ` of the type `Person`. diff --git a/apps/exhibition-live/stories/maintenance/DataImport.mdx b/apps/exhibition-live/stories/maintenance/DataImport.mdx new file mode 100644 index 00000000..2a064906 --- /dev/null +++ b/apps/exhibition-live/stories/maintenance/DataImport.mdx @@ -0,0 +1,22 @@ +import { Meta } from "@storybook/blocks"; + + + + +# Importing Data from other Data Stores + +Two kinds of import commands are available in the EDB Cli. The `flatImport` command will import flat table structured documents +for example CSV files and the `import` command will recursively import data from another data store. + +```bash +bun run cli import Exhibition --importFrom oxigraph +``` +The import command will recursively import data from another data store. + +will import all documents of the type `Exhibition` from the oxigraph data store. +That means it will also import all related documents, like `Person` or `Place`, and their relations +in a recursive manner. + + + + diff --git a/apps/exhibition-live/stories/maintenance/DataMapping.mdx b/apps/exhibition-live/stories/maintenance/DataMapping.mdx new file mode 100644 index 00000000..3202b341 --- /dev/null +++ b/apps/exhibition-live/stories/maintenance/DataMapping.mdx @@ -0,0 +1,361 @@ +import { Meta } from "@storybook/blocks"; + + + +The typical work with a domain specific database is to map data from a secondary data source into +the primary datasource, thus making the data available for the specific use case and normalize the +data. + +This is done, when linking data to entities in secondary databases like the GND, Wikidata, OSM, etc. +but also, when importing data from other sources like CSV, JSON, etc. + +The EDB Framework tries to facilitate the mapping by specifying a mapping schema, that can used to map +tree-like data structures or flat data structures into the primary data model. + +A mapping schema is a JSON object, that specifies the mapping of the data, based on certain mapping strategies. + +# Data Mapping Strategies + +## Overview + +The EDB Framework facilitates mapping data from secondary data sources into a primary data model by specifying a JSON-based mapping schema. This schema supports both tree-like and flat data structures and allows for various mapping strategies to be applied. Below are the strategies implemented in the framework along with their detailed descriptions and options. + +### Mapping Strategies + +#### 1. Concatenate Strategy + +**ID:** `concatenate` + +**Description:** Concatenates an array of strings into a single string. + +**Options:** +- `separator` (optional): A string used to separate the concatenated values. + +**Example:** +```json +{ + "strategy": { + "id": "concatenate", + "options": { + "separator": ", " + } + } +} +``` + +#### 2. Take First Strategy + +**ID:** `takeFirst` + +**Description:** Takes the first element of an array. + +**Options:** None + +**Example:** +```json +{ + "strategy": { + "id": "takeFirst" + } +} +``` + +#### 3. Append Strategy + +**ID:** `append` + +**Description:** Appends an array of values to another array. + +**Options:** +- `allowDuplicates` (optional): A boolean indicating whether duplicates are allowed. +- `subFieldMapping` (optional): An object specifying a mapping for subfields. + +**Example:** +```json +{ + "strategy": { + "id": "append", + "options": { + "allowDuplicates": false + } + } +} +``` + +#### 4. Create Entity With Authoritative Link Strategy + +**ID:** `createEntityWithAuthoritativeLink` + +**Description:** +This strategy creates an entity with an authoritative link. It looks up entities within an authoritative source and, if they exist, maps them to the local data model. If they do not exist, it creates a new entity with a link to the authoritative source. + +**Options:** +- `typeIRI` (optional): The IRI of the entity type. +- `mainProperty`: An object containing: +- `offset` (optional): The offset of the main property in the source data. +- `authorityFields`: An array of objects containing: +- `offset`: The offset in the source data. +- `authorityIRI` (optional): The IRI of the authority. +- `authorityLinkPrefix` (optional): The prefix for the authority link. + +**Example:** +```json +{ + "strategy": { + "id": "createEntityWithAuthoritativeLink", + "options": { + "typeIRI": "http://example.org/type", + "mainProperty": { + "offset": 0 + }, + "authorityFields": [ + { + "offset": 1, + "authorityIRI": "http://example.org/authority", + "authorityLinkPrefix": "http://example.org/link/" + } + ] + } + } +} +``` + +#### 5. Create Entity With Reification From String Strategy + +**ID:** `createEntityWithReificationFromString` + +**Description:** Creates an entity with reification from a string. + +**Options:** +- `typeIRI` (optional): The IRI of the entity type. +- `mainProperty`: An object containing: +- `property`: The main property. +- `offset` (optional): The offset of the main property in the source data. +- `mapping` (optional): An object specifying a strategy for the main property. +- `statementProperties`: An array of objects containing: +- `property`: The statement property. +- `offset`: The offset in the source data. +- `mapping` (optional): An object specifying a strategy for the statement property. + +**Example:** +```json +{ + "strategy": { + "id": "createEntityWithReificationFromString", + "options": { + "typeIRI": "http://example.org/type", + "mainProperty": { + "property": "mainProperty", + "offset": 0 + }, + "statementProperties": [ + { + "property": "statementProperty1", + "offset": 1 + }, + { + "property": "statementProperty2", + "offset": 2 + } + ] + } + } +} +``` + +#### 6. Create Entity From String Strategy + +**ID:** `createEntityFromString` + +**Description:** Creates an entity from a string. + +**Options:** +- `typeIRI` (optional): The IRI of the entity type. +- `typeName` (optional): The name of the entity type. + +**Example:** +```json +{ + "strategy": { + "id": "createEntityFromString", + "options": { + "typeIRI": "http://example.org/type", + "typeName": "ExampleType" + } + } +} +``` + +#### 7. Create Entity Strategy + +**ID:** `createEntity` + +**Description:** Creates an entity. + +**Options:** +- `typeIRI` (optional): The IRI of the entity type. +- `typeName` (optional): The name of the entity type. +- `single` (optional): A boolean indicating if only a single entity should be created. +- `subFieldMapping`: An object specifying mappings for subfields. + +**Example:** +```json +{ + "strategy": { + "id": "createEntity", + "options": { + "typeIRI": "http://example.org/type", + "typeName": "ExampleType", + "single": true, + "subFieldMapping": { + "fromSelf": [], + "fromEntity": [] + } + } + } +} +``` + +#### 8. Constant Strategy + +**ID:** `constant` + +**Description:** Returns a constant value. + +**Options:** +- `value`: The constant value to return. + +**Example:** +```json +{ + "strategy": { + "id": "constant", + "options": { + "value": "constantValue" + } + } +} +``` + +#### 9. Date String to Special Int Strategy + +**ID:** `dateStringToSpecialInt` + +**Description:** Converts a date string to a special integer format. + +**Options:** None + +**Example:** +```json +{ + "strategy": { + "id": "dateStringToSpecialInt" + } +} +``` + +#### 10. Date Array to Special Int Strategy + +**ID:** `dateArrayToSpecialInt` + +**Description:** Converts a date array to a special integer format. + +**Options:** None + +**Example:** +```json +{ + "strategy": { + "id": "dateArrayToSpecialInt" + } +} +``` + +#### 11. Split Strategy + +**ID:** `split` + +**Description:** Splits a string into an array of substrings. + +**Options:** +- `separator` (optional): The separator to use for splitting the string. +- `mapping` (optional): An object specifying a strategy for each substring. + +**Example:** +```json +{ + "strategy": { + "id": "split", + "options": { + "separator": ",", + "mapping": { + "strategy": { + "id": "takeFirst" + } + } + } + } +} +``` + +#### 12. Exists Strategy + +**ID:** `exists` + +**Description:** Checks if the source data exists (is not `null` or `undefined`). + +**Options:** None + +**Example:** +```json +{ + "strategy": { + "id": "exists" + } +} +``` + +#### 13. Date Range String to Special Int Strategy + +**ID:** `dateRangeStringToSpecialInt` + +**Description:** Converts a date range string to a special integer format, extracting either the start or end date. + +**Options:** +- `extractElement`: Specifies whether to extract the start or end date. Possible values are `"start"` or `"end"`. + +**Example:** +```json +{ + "strategy": { + "id": "dateRangeStringToSpecialInt", + "options": { + "extractElement": "start" + } + } +} +``` + +### Strategy Function Map + +The framework includes a strategy function map that associates each strategy ID with its corresponding function. This map is used internally to resolve and execute the appropriate strategy function based on the mapping schema. + +```javascript +export const strategyFunctionMap: { [strategyId: string]: StrategyFunction } = { + concatenate, + takeFirst, + append, + createEntity, + createEntityFromString, + createEntityWithReificationFromString, + createEntityWithAuthoritativeLink, + dateStringToSpecialInt, + dateRangeStringToSpecialInt, + exists: existsStrategy, + constant: constantStrategy, + split: splitStrategy, + dateArrayToSpecialInt, +}; +``` + +This documentation provides an overview of the available mapping strategies in the EDB Framework, their options, and examples of how they can be used in a mapping schema. These strategies allow for flexible and powerful data transformations when importing and linking data from various sources into a primary data model. diff --git a/apps/exhibition-live/stories/maintenance/NormData.mdx b/apps/exhibition-live/stories/maintenance/NormData.mdx new file mode 100644 index 00000000..93834609 --- /dev/null +++ b/apps/exhibition-live/stories/maintenance/NormData.mdx @@ -0,0 +1,27 @@ +import { Meta } from "@storybook/blocks"; + + + +# Mapping from authorities and secondary databases + +The UI and the Backend makes use of declarative mapping configurations and a set of extensible +mapping Strategies to map secondary databases and authorities to the internal data model. + +Items, that have been found in an external database are being mapped according to the external mapping declaration, that exists +in the configuration of the manifestation of the EDB-Database. + +## Usage throughout the application + +Those declarative mappings are being used when importing data and when manually linking items to external databases. +Typically, when entering a historical record into the database, relations to persons, organisations, places, etc. are being created. +The mapping will then not only record the link to the external database itself but also map the external data to the internal data model. + +This is done when linking data using the [Similarity Finder](/docs/development-similarity-finder--docs) or when importing data from other sources. + +## Mapping Declaration + +when importing Data from other sources like tables, CSV-Files, etc. the configured mapping declaration is being used as well. + +## Adding New Mappings + +## Adding new sources to the Similarity Finder diff --git a/apps/exhibition-live/vite.config.ts b/apps/exhibition-live/vite.config.ts new file mode 100644 index 00000000..2b657806 --- /dev/null +++ b/apps/exhibition-live/vite.config.ts @@ -0,0 +1,23 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react-swc"; +import { NodeGlobalsPolyfillPlugin } from "@esbuild-plugins/node-globals-polyfill"; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], + optimizeDeps: { + esbuildOptions: { + // Node.js global to browser globalThis + define: { + global: "globalThis", + }, + // Enable esbuild polyfill plugins + plugins: [ + // @ts-ignore + NodeGlobalsPolyfillPlugin({ + process: true, + }), + ], + }, + }, +}); diff --git a/apps/exhibition-live/vite.env.d.ts b/apps/exhibition-live/vite.env.d.ts new file mode 100644 index 00000000..63a5f78d --- /dev/null +++ b/apps/exhibition-live/vite.env.d.ts @@ -0,0 +1,14 @@ +/// + +interface ImportMetaEnv { + readonly VITE_SPARQL_ENDPOINT: string; + readonly VITE_SPARQL_ENDPOINT_LABEL: string; + readonly VITE_SPARQL_ENDPOINT_PROVIDER: string; + readonly VITE_GOOGLE_CLIENT_ID: string; + readonly VITE_APP_MANIFESTATION: "exhibition" | "kulinarik"; + // more env variables... +} + +interface ImportMeta { + readonly env: ImportMetaEnv; +} diff --git a/apps/exhibition-live/vite/App.tsx b/apps/exhibition-live/vite/App.tsx new file mode 100644 index 00000000..b7fd0d74 --- /dev/null +++ b/apps/exhibition-live/vite/App.tsx @@ -0,0 +1,69 @@ +import { AdbProvider, store } from "@slub/edb-state-hooks"; +import { Provider } from "react-redux"; +import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; +import "dayjs/locale/de"; +import "dayjs/locale/en"; +import { BASE_IRI, PUBLIC_BASE_PATH } from "../components/config"; +import { EditEntityModal } from "../components/form/edit/EditEntityModal"; +import { SnackbarProvider } from "notistack"; +import { useRouterHook } from "./useRouterHook"; +import React from "react"; +import { LocalizationProvider } from "@mui/x-date-pickers"; +import { exhibitionConfig } from "../components/config/exhibitionAppConfig"; +import { kulinarikAppConfig } from "../components/config/kulinarikAppConfig"; +import { envToSparqlEndpoint } from "@slub/edb-ui-utils"; +import { EntityDetailModal } from "@slub/edb-advanced-components"; +import { SimilarityFinder } from "../components/form/similarity-finder"; +import { SemanticJsonFormNoOps } from "@slub/edb-linked-data-renderer"; +import { GoogleOAuthProvider } from "@react-oauth/google"; +import NiceModal from "@ebay/nice-modal-react"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { ThemeComponent } from "@slub/edb-default-theme"; + +import "react-json-view-lite/dist/index.css"; +import { availableAuthorityMappings } from "@slub/exhibition-schema"; + +export const queryClient = new QueryClient(); + +const sparqlEndpoint = envToSparqlEndpoint(import.meta.env, "VITE"); +const googleClientId = import.meta.env.VITE_GOOGLE_CLIENT_ID; + +const appConfig = + import.meta.env.VITE_APP_MANIFESTATION === "kulinarik" + ? kulinarikAppConfig + : exhibitionConfig; + +export const App = ({ children }: { children?: React.ReactNode }) => { + return ( + + + + + + + + {children} + + + + + + + + ); +}; diff --git a/apps/exhibition-live/vite/main.tsx b/apps/exhibition-live/vite/main.tsx new file mode 100644 index 00000000..c0dd69e3 --- /dev/null +++ b/apps/exhibition-live/vite/main.tsx @@ -0,0 +1,54 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; +import { App } from "./App"; +import { createBrowserRouter, RouterProvider } from "react-router-dom"; +import { CreatePage } from "./pages/Create"; +import { initReactI18next } from "react-i18next"; +import i18n from "i18next"; +import { ListPage } from "./pages/List"; +import Backend from "i18next-http-backend"; +import { ImportPage } from "../components/importExport/ImportPage"; + +const Home = () => { + return ( +
+

Home

+
+ ); +}; + +let router = createBrowserRouter([ + { + path: "/", + element: , + }, + { + path: ":locale/create/:typeName", + element: , + }, + { + path: ":locale/list/:typeName", + element: , + }, + { + path: ":locale/import", + element: , + }, +]); + +i18n + .use(Backend) + .use(initReactI18next) // passes i18n down to react-i18next + .init({ + lng: "de", + ns: ["translation", "table"], + defaultNS: "translation", + }); + +ReactDOM.createRoot(document.getElementById("root")!).render( + + + Loading...

} /> +
+
, +); diff --git a/apps/exhibition-live/vite/pages/Create.tsx b/apps/exhibition-live/vite/pages/Create.tsx new file mode 100644 index 00000000..73fadd5a --- /dev/null +++ b/apps/exhibition-live/vite/pages/Create.tsx @@ -0,0 +1,65 @@ +import { useSearchParams } from "react-router-dom"; +import React, { useEffect, useMemo, useState } from "react"; +import { decodeIRI } from "@slub/edb-core-utils"; +import { MainLayout } from "../../components/layout/main-layout"; +import { Button, Hidden } from "@mui/material"; +import { Visibility, VisibilityOff } from "@mui/icons-material"; +import TypedForm from "../../components/content/main/TypedForm"; +import { + useAdbContext, + useFormEditor, + useModifiedRouter, + useSettings, +} from "@slub/edb-state-hooks"; +import NiceModal from "@ebay/nice-modal-react"; + +export const CreatePage = () => { + const [searchParam] = useSearchParams(); + const { + query: { typeName }, + } = useModifiedRouter(); + const { createEntityIRI, typeNameToTypeIRI } = useAdbContext(); + const [entityIRI, setEntityIRI] = useState( + createEntityIRI(typeName as string), + ); + useEffect(() => { + const encID = searchParam.get("encID"); + const id = typeof encID === "string" ? decodeIRI(encID) : undefined; + const newURI = id || createEntityIRI(typeName as string); + setEntityIRI(newURI); + }, [setEntityIRI, typeName, searchParam]); + const { features } = useSettings(); + const { previewEnabled, togglePreview } = useFormEditor(); + const typeIRI: string | undefined = useMemo( + () => typeNameToTypeIRI(typeName as string), + [typeName], + ); + + return ( + + + + + } + > + {typeIRI && typeName && entityIRI && ( + <> + + + )} + + + ); +}; diff --git a/apps/exhibition-live/vite/pages/List.tsx b/apps/exhibition-live/vite/pages/List.tsx new file mode 100644 index 00000000..33896d34 --- /dev/null +++ b/apps/exhibition-live/vite/pages/List.tsx @@ -0,0 +1,23 @@ +import { MainLayout } from "../../components/layout/main-layout"; +import React from "react"; +import NiceModal from "@ebay/nice-modal-react"; +import { useModifiedRouter } from "@slub/edb-state-hooks"; +import { SemanticTable } from "@slub/edb-table-components"; +import { tableConfig } from "../../components/config/tableConfig"; + +export const ListPage = () => { + const { + query: { typeName }, + } = useModifiedRouter(); + return ( + + + {/* eslint-disable-next-line react/jsx-no-undef */} + + + + ); +}; diff --git a/apps/exhibition-live/vite/useRouterHook.ts b/apps/exhibition-live/vite/useRouterHook.ts new file mode 100644 index 00000000..46a16772 --- /dev/null +++ b/apps/exhibition-live/vite/useRouterHook.ts @@ -0,0 +1,55 @@ +import { ModRouter } from "@slub/edb-global-types"; +import { + Location, + Params, + useLocation, + useNavigate, + useParams, + useSearchParams, +} from "react-router-dom"; +import { useCallback } from "react"; + +/** + * Function converts path like /user/123 to /user/:id + */ +const getRoutePath = (location: Location, params: Params): string => { + const { pathname } = location; + + if (!Object.keys(params).length) { + return pathname; // we don't need to replace anything + } + + let path = pathname; + Object.entries(params).forEach(([paramName, paramValue]) => { + if (paramValue) { + path = path.replace(paramValue, `:${paramName}`); + } + }); + return path; +}; + +export const useRouterHook: () => ModRouter = () => { + const navigate = useNavigate(); + const [searchParams, setSearchParams] = useSearchParams(); + const push: ModRouter["push"] = useCallback( + async (path, as) => navigate(path), + [navigate], + ); + const replace: ModRouter["replace"] = useCallback( + async (path, as) => navigate(path, { replace: true }), + [navigate], + ); + const params = useParams(); + const location = useLocation(); + const asPath = getRoutePath(location, params); + + return { + push, + replace, + asPath, + pathname: location.pathname, + query: params, + searchParams, + setSearchParams, + }; +}; diff --git a/bun.lockb b/bun.lockb index 0b812f1d..ab017a6a 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/docker-compose.yml b/docker-compose.yml index c39a205d..4b25a3ed 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,19 @@ version: '3' services: + nginx: + image: nginx:alpine + volumes: + - ./docker/nginx.config:/etc/nginx/conf.d/default.conf + ports: + - "7878:80" + depends_on: + - oxigraph + oxigraph: + image: ghcr.io/oxigraph/oxigraph:latest + platform: linux/amd64 + volumes: + - ./docker/data:/data nodejs: build: context: . @@ -8,9 +21,11 @@ services: container_name: exhibition-dev env_file: .env ports: - - "3000:3000" + - 3000:3000 + - 5173:5173 + - 6006:6006 volumes: - .:/app stdin_open: true tty: true - command: /bin/bash -c 'bun i && bun run dev --filter="./packages/*" & (sleep 10 && bun run dev --filter="/apps/exhibition-live")' + command: /bin/bash -c 'bun i && bun run build:packages && bun run dev:vite' diff --git a/docker/nginx.config b/docker/nginx.config index 22c5d7f7..86a40b1e 100644 --- a/docker/nginx.config +++ b/docker/nginx.config @@ -6,6 +6,7 @@ server listen 80; server_name localhost; location / { + client_max_body_size 50M; if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; @@ -36,4 +37,4 @@ server proxy_pass http://oxigraph:7878/; } -} \ No newline at end of file +} diff --git a/docker/scripts/export-triples.sh b/docker/scripts/export-triples.sh index d45fcd2e..0f4f8db4 100755 --- a/docker/scripts/export-triples.sh +++ b/docker/scripts/export-triples.sh @@ -10,27 +10,35 @@ function help { echo " -e endpoint-url The url of the endpoint to query. Default: http://localhost:7878/query" echo " -o output-file The file to write the triples to. Default: dump.nt" echo " -f format-mime The mime type of the output file. Default: application/n-triples" + echo " -d default-prefix The default prefix to use in the query. Default: http://example.org/" echo " -h Show this help message" exit 0 } #parse options -while getopts "e:o:h" opt; do +while getopts "e:o:f:d:h" opt; do case ${opt} in e ) endpoint_url=$OPTARG;; o ) output_file=$OPTARG;; f ) format_mime=$OPTARG;; + d ) default_prefix=$OPTARG;; h ) help;; \? ) help;; esac done +prefixes="" + +if [ -n "$default_prefix" ]; then + prefixes="PREFIX : <$default_prefix>" +fi curl "${endpoint_url}" \ - -H 'Accept: ${format_mime},*/*;q=0.9' \ + -H "Accept: ${format_mime},*/*;q=0.9" \ -H 'Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7' \ -H 'Connection: keep-alive' \ -H 'Content-Type: application/x-www-form-urlencoded' \ - --data-raw 'query=CONSTRUCT%20%7B%20%3Fsub%20%3Fpred%20%3Fobj%20.%20%7D%20WHERE%20%7B%0A%20%20%3Fsub%20%3Fpred%20%3Fobj%20.%0A%7D' \ + --verbose \ + --data-urlencode "query=${prefixes} CONSTRUCT { ?sub ?pred ?obj . } WHERE { ?sub ?pred ?obj .}" \ --compressed \ --output ${output_file} diff --git a/flake.lock b/flake.lock index fa6bbfdc..2684eab1 100644 --- a/flake.lock +++ b/flake.lock @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1711703276, - "narHash": "sha256-iMUFArF0WCatKK6RzfUJknjem0H9m4KgorO/p3Dopkk=", + "lastModified": 1721562059, + "narHash": "sha256-Tybxt65eyOARf285hMHIJ2uul8SULjFZbT9ZaEeUnP8=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "d8fe5e6c92d0d190646fb9f1056741a229980089", + "rev": "68c9ed8bbed9dfce253cc91560bf9043297ef2fe", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 471a8fdb..6978c078 100644 --- a/flake.nix +++ b/flake.nix @@ -17,13 +17,18 @@ nodePackages_latest.prisma prisma-engines #jetbrains.idea-ultimate + apache-jena + librdf_raptor2 bun openssl appimage-run + tree ]; + LD_LIBRARY_PATH = "${pkgs.stdenv.cc.cc.lib}/lib"; PRISMA_QUERY_ENGINE_BINARY = "${pkgs.prisma-engines}/bin/query-engine"; PRISMA_QUERY_ENGINE_LIBRARY = "${pkgs.prisma-engines}/lib/libquery_engine.node"; PRISMA_SCHEMA_ENGINE_BINARY = "${pkgs.prisma-engines}/bin/schema-engine"; + CYPRESS_RUN_BINARY = "${pkgs.cypress}/bin/Cypress"; }; } ); diff --git a/manifestation/exhibition-sparql-config/src/index.ts b/manifestation/exhibition-sparql-config/src/index.ts index 1ce5065b..535bce3b 100644 --- a/manifestation/exhibition-sparql-config/src/index.ts +++ b/manifestation/exhibition-sparql-config/src/index.ts @@ -3,18 +3,19 @@ import { Config } from "@slub/edb-global-types"; const BASE_IRI = "http://ontologies.slub-dresden.de/exhibition#"; export const sladb = namespace(BASE_IRI); -export const slent = namespace(`${BASE_IRI}/entity/`); +export const slent = namespace( + `http://ontologies.slub-dresden.de/exhibition/entity#`, +); export const defaultPrefix = sladb[""].value; export default { BASE_IRI, - API_URL: "http://sdvahndmgtest.slub-dresden.de:8000/graphql", namespaceBase: "http://ontologies.slub-dresden.de/exhibition#", namespace: namespace("http://ontologies.slub-dresden.de/exhibition#"), defaultPrefix: "http://ontologies.slub-dresden.de/exhibition#", walkerOptions: { - maxRecursion: 8, - maxRecursionEachRef: 8, + maxRecursion: 6, + maxRecursionEachRef: 6, skipAtLevel: 10, omitEmptyArrays: true, omitEmptyObjects: true, @@ -22,6 +23,9 @@ export default { defaultJsonldContext: { "@vocab": defaultPrefix, xs: "http://www.w3.org/2001/XMLSchema#", + id: { + "@type": "@id", + }, image: { "@type": "xs:anyURI", }, @@ -30,8 +34,8 @@ export default { prefixes: { [""]: sladb, slent }, }, sparqlEndpoint: { - label: "Ausstellungsdatenbank", - endpoint: "https://ausstellungsdatenbank.kuenste.live/query", + label: "Ausstellungsdatenbank Lokal", + endpoint: "http://localhost:7878/query", provider: "oxigraph", active: true, }, diff --git a/manifestation/exhibition-sparql-config/tsup.config.js b/manifestation/exhibition-sparql-config/tsup.config.js index 3dd890ed..85b8dcc3 100644 --- a/manifestation/exhibition-sparql-config/tsup.config.js +++ b/manifestation/exhibition-sparql-config/tsup.config.js @@ -1,3 +1,5 @@ -import config from "@slub/edb-tsup-config/tsup.config.js"; +import { makeConfigWithExternals } from "@slub/edb-tsup-config/tsup.config.js"; +import pkg from "./package.json"; +const config = makeConfigWithExternals(pkg); export default config; diff --git a/manifestation/exhibition/import/Konvolut_NewYork_2024-07-14.csv b/manifestation/exhibition/import/Konvolut_NewYork_2024-07-14.csv new file mode 100644 index 00000000..de4b8998 --- /dev/null +++ b/manifestation/exhibition/import/Konvolut_NewYork_2024-07-14.csv @@ -0,0 +1,994 @@ +,Name Kiste,Medientyp (Konvulut),Ressourcentyp,Titel (Konvulut),Beschreibung Konvolut,Ausstellungstitel 1,Untertitel 1,Ausstellung (GND),Ausstellungstitel 2,Untertitel 2,Ausstellungstyp 1,Ausstellungskategorie 1,Ausstellungstyp 2,Ausstellungskategorie ,Serie/Veranstaltungsreihe,Serie/Veranstaltungsreihe (GND),Genre 1,Genre 1 (GND),Genre 2,Genre 2 (GND),Genre 3,Genre 3 (GND),Genre 4,Genre 4 (GND),Genre 5,Genre 5 (GND),Ort der Ausstellung (geografisch) 1,Ort der Ausstellung (geografisch) 1 (GND),Ort der Ausstellung (geografisch) 2,Ort der Ausstellung (geografisch) 2 (GND),Ort der Ausstellung (geografisch) 3,Ort der Ausstellung (geografisch) 3 (GND),Ort der Ausstellung (geografisch) 4,Ort der Ausstellung (geografisch) 4 (GND),Ort der Ausstellung (Institution) 1,Ort der Ausstellung (Institution) (GND)1,Ort der Ausstellung (Institution) 2,Ort der Ausstellung (Institution) 3,Ort der Ausstellung (Institution) 4,Ort der Ausstellung (Institution) 5,Ort der Ausstellung (Institution) 6,Ort der Ausstellung (Institution) 7,Aktuell Ort der Ausstellung (Institution) 1,Aktuell Ort der Ausstellung (Institution) 2,Aktuell Ort der Ausstellung (Institution) 3,Erscheinungsort,Originaltitel,Beteiligte Person 1 (Name),Beteiligte Person 1 (GND-Nummer),Beteiligte Person 1 (Rolle 1),Beteiligte Person 1 (Rolle 2),Beteiligte Person 2 (Name),Beteiligte Person 2 (GND-Nummer),Beteiligte Person 2 (Rolle 1),Beteiligte Person 3,Rolle,Beteiligte Person 4,Rolle,Beteiligte Person 5,Rolle,Beteiligte Person 6,Rolle,Beteiligte Person 7,Rolle,Beteiligte Person 7,Rolle,Beteiligte Person 8,Rolle,Beteiligte Person 9,Rolle,Beteiligte Person 10,Rolle,Beteiligte Person 11,Rolle,Beteiligte Person 12,Rolle,Beteiligte Person 13,Rolle,Beteiligte Person 14,Rolle,Beteiligte Person 15,Rolle,Beteiligte Person 16,Rolle,Beteiligte Person 17,Rolle,Beteiligte Person 18,Rolle,Beteiligte Person 19,Rolle,Beteiligte Person 20,Rolle,Beteiligte Person 21,Rolle,Beteiligte Person 22,Rolle,Beteiligte Person 23,Rolle,Beteiligte Person 24,Rolle,Beteiligte Person 25,Rolle,Beteiligte Person 26,Rolle,Beteiligte Person 27,Rolle,Beteiligte Person 28,Rolle,Beteiligte Person 29,Rolle,Beteiligte Person 30,Rolle,Beteiligte Person 31,Rolle,Beteiligte Person 32,Rolle,Beteiligte Person 33,Rolle,Beteiligte Person 34,Rolle,Beteiligte Person 35,Rolle,Beteiligte Person 36,GND,Rolle,Beteiligte Person 37,Rolle,Beteiligte Person 38,Rolle,Beteiligte Person 39,Rolle,Beteiligte Person 40,Rolle,Beteiligte Person 41,Rolle,Beteiligte Person 42,Rolle,Beteiligte Person 43,Rolle,Beteiligte Person 44,Rolle,Beteiligte Person 45,Rolle,Beteiligte Person 46,Rolle,Beteiligte Person 47,Rolle,Beteiligte Person 48,Rolle,Beteiligte Person 49,Rolle,Beteiligte Person 50,Rolle,Beteiligte Person 51,Rolle,Beteiligte Person 52,Rolle,Beteiligte Person 53,Rolle,Beteiligte Person 54,Rolle,Beteiligte Körperschaft 1,Rolle,Beteiligte Körperschaft 2,,Viaf,Rolle,Beteiligte Körperschaft 3,Rolle,Beteiligte Körperschaft 4,Rolle,Beteiligte Körperschaft 5,Rolle,Beteiligte Körperschaft 6,Rolle,Beteiligte Körperschaft 7,Rolle,Beteiligte Körperschaft 8,Rolle,Aktuell Beteiligte Körperschaft 1,Aktuell Beteiligte Körperschaft 2,Aktuell Beteiligte Körperschaft 3,Zusatz Beteiligte Körperschaft 1,Datierung,Widmung F. C. Gundlach,Widmung Andere,Ausstellungsdatum (von...) 1,Tag,Monat,Jahr,Ausstellungsdatum (...bis) 1,Tag,Monat,Jahr,"Weitere Datumsangaben (Vernissage, Finissage, ...) 1",Tag,Monat,Jahr,Ausstellungsdatum (von...) 2,Tag,Monat,Jahr,Ausstellungsdatum (...bis) 2,Tag,Monat,Jahr,"Weitere Datumsangaben (Vernissage, Finissage, ...) 2",Tag,Monat,Jahr,Ausstellungsdatum (von...) 3,Tag,Monat,Jahr,Ausstellungsdatum (...bis) 3,Tag,Monat,Jahr,"Weitere Datumsangaben (Vernissage, Finissage, ...) 3",Tag,Monat,Jahr,Ausstellungsdatum (von...) 4,Tag,Monat,Jahr,Ausstellungsdatum (...bis) 4,Tag,Monat,Jahr,"Weitere Datumsangaben (Vernissage, Finissage, ...) 4",Tag,Monat,Jahr,Schlagwort 1,Schlagwort 2,Schlagwörter 3,Schlagwörter 4,Schlagwort 5,Schlagwort 6,Beschreibung,Sprache 1,Sprache 2,Sprache 3,Signatur,RVK-Notation,K10PlusPPN,SWB-ID,Sachgebiet/SSG Nummer/FID-Kennzeichen ,Permalink,DOI-Digitalisat ,Weblink/URL,Ressource +https://gagosian.com/exhibitions/2013/works-of-the-jenney-archive/,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Works of the Jenney Archive, Gagosian Gallery, 7.3.2013 - 27.4.2013",Works of the Jenney Archive,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Jenney, Neil",120360500,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,3,2013,,27,4,2013,Vernissage,7,3,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +https://gagosian.com/exhibitions/2008/prefab/,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Prefab: Richard Artschwager, Alighiero E Boetti, Mike Kelley, Martin Kippenberger, Jeff Koons, Sherrie Levine, Richard Prince, Rudolf Stingel, Rosemarie Trockel, Gagosian Gallery, 26.2.2008 - 19.4.2008",Prefab,"Richard Artschwager, Alighiero E Boetti, Mike Kelley, Martin Kippenberger, Jeff Koons, Sherrie Levine, Richard Prince, Rudolf Stingel, Rosemarie Trockel",,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,4037220-0,Objektkunst,4131740-3,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Artschwager, Richard",118848127,Künstler:in,,"Boetti, Alighiero",118852418,Künstler:in,"Kelley, Mike",Künstler:in,"Kippenberger, Martin",Künstler:in,"Koons, Jeff",Künstler:in,"Levine, Sherrie",Künstler:in,"Prince, Richard",Künstler:in,"Stingel, Rudolf",Künstler:in,"Trockel, Rosemarie",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,26,2,2008,,19,4,2008,Vernissage,26,2,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,Objektkunst,,,,,Englisch,,,,,,,,,,, +https://gagosian.com/exhibitions/2007/paul-noble-dot-to-dot/,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Paul Noble. Dot to Dot, Gagosian Gallery, 20.9.2007 - 27.10.2007",Paul Noble. Dot to Dot,,10203782-6,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,4021845-4,Keramik,4030270-2,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Noble, Paul",119405202,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,20,9,2007,,27,10,2007,Vernissage,20,9,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,Keramik,,,,,Englisch,,,,,,,,,,, +https://gagosian.com/exhibitions/2007/douglas-gordon-self-portrait-of-you-me-after-the-factory/,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Douglas Gordon - self-portrait of you + me, after the factory, Gagosian Gallery, 31.10.2007 - 15.12.2007","Douglas Gordon - self-portrait of you + me, after the factory",,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Gordon, Douglas",120994011,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,31,10,2007,,15,12,2007,Vernissage,31,10,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +https://gagosian.com/exhibitions/2012/ed-ruscha/,New York,Blatt/unbewegtes B ../../manifestation/exhibition/import/ild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Ed Ruscha, Gagosian Gallery, 7.11.2012 - 12.1.2013",Ed Ruscha,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,Objektkunst,4131740-3,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Ruscha, Ed",119255588,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,11,2012,,12,1,2013,Vernissage,7,11,2012,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,Objektkunst,,,,,Englisch,,,,,,,,,,, +https://gagosian.com/exhibitions/2003/richard-serra-wake-blindspot-catwalk-vice-versa/,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Richard Serra - Wake, Blindspot, Catwalk, Vice-Versa , Gagosian Gallery, 20.9.2003 - 25.10.2003","Richard Serra - Wake, Blindspot, Catwalk, Vice-Versa ",,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Serra, Richard",118796267,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,20,9,2003,,25,10,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +https://gagosian.com/exhibitions/2012/richard-phillips/,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Richard Phillips, Gagosian Gallery, 11.9.2012 - 20.10.2012",Richard Phillips,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Phillips, Richard",122410483,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,9,2012,,20,10,2012,Vernissage,11,9,2012,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +https://gagosian.com/exhibitions/2013/painted-on-21st-street-helen-frankenthaler-from-1950-to-1959/,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Painted on 21st street - Helen Frankenthaler: from 1950 to 1959, Gagosian Gallery, 8.3.2013 - 13.4.2013",Painted on 21st street - Helen Frankenthaler,from 1950 to 1959,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Elderfield, John",104959486X,Kurator:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,The Estate of Helen Frankenthaler,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,8,3,2013,,13,4,2013,Vernissage,8,3,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Richard Serra - New Sculpture, Gagosian Gallery, 26.10.2013 - 25.1.2014",Richard Serra - New Sculpture,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Serra, Richard",118796267,Bildhauer:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,26,10,2013,,25,1,2014,Vernissage,25,10,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Renzo Piano Building Workshop : Fragments, Gagosian Gallery, 27.6.2013 - 2.8.2013",Renzo Piano Building Workshop ,Fragments,,,,Einzelausstellung,Sonderausstellung,,,,,Architektur,4002851-3,Fotografie,4045895-7,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Piano, Renzo",11889787X,Architekt:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,Fondazione Renzo Piano,,,Kooperationspartner,Renzo Piano Building Workshop,Architekturbüro,,,,,,,,,,,,,,,,,,,27,6,2013,,2,8,2013,Vernissage,27,6,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Architektur,Fotografie,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Thomas Houseago - The Medusa and Other Heads, Gagosian Gallery, 12.5.2015 - 13.6.2015",Thomas Houseago - The Medusa and Other Heads,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,Park & 75,,,,,,,,,,,"Houseago, Thomas",139434836,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,12,5,2015,,13,6,2015,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Atemwende: Edmund de Waal, Gagosian Gallery, 12.9.2013 - 19.10.2013",Atemwende,Edmund de Waal,1047895404,,,Einzelausstellung,Sonderausstellung,,,,,Keramik,4030270-2,Objektkunst,4131740-3,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"De Waal, Edmund",141680105,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,12,9,2013,,19,10,2013,Vernissage,12,9,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Keramik,Objektkunst,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Marcel Duchamp, Gagosian Gallery, 26.6.2014 - 8.8.2014",Marcel Duchamp,,1075466989,,,Einzelausstellung,Sonderausstellung,,,,,Objektkunst,4131740-3,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Duchamp, Marcel",11852772X,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,26,6,2014,,8,8,2014,Vernissage,26,6,2014,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Objektkunst,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Urs Fischer - last supper, Gagosian Gallery, 3.4.2014 - 8.5.2014",Urs Fischer - last supper,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,Park & 75,,,,,,,,,,,"Fischer, Urs",122387821,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,4,2014,,8,5,2014,Vernissage,3,4,2014,,3,4,2014,,23,5,2014,Vernissage,3,4,2014,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Urs Fischer - mermaid / pig / bro w/ hat, Gagosian Gallery, 3.4.2014 - 8.5.2014",Urs Fischer - mermaid / pig / bro w/ hat,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,Park & 75,,,,,,,,,,,"Fischer, Urs",122387821,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,4,2014,,8,5,2014,Vernissage,3,4,2014,,3,4,2014,,23,5,2014,Vernissage,3,4,2014,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Henry Moore - Late Large Forms, Gagosian Gallery, 9.11.2012 - 5.1.2013",Henry Moore - Late Large Forms,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Moore, Henry",118583875,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,The Henry Moore Foundation,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,9,11,2012,,5,1,2013,Vernissage,9,11,2012,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Mike Kelley - Horizontal Tracking Shots, Gagosian Gallery, 7.11.2009 - 23.12.2009",Mike Kelley - Horizontal Tracking Shots,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Kelley, Mike",119052555,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,11,2009,,23,12,2009,Vernissage,7,11,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Cy Twombly - Eight Sculptures, Gagosian Gallery, 15.9.2009 - 31.10.2009",Cy Twombly - Eight Sculptures,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Twombly, Cy",118624865,Bildhauer:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,15,9,2009,,31,10,2009,Vernissage,15,9,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Proud Flesh - Sally Mann, Gagosian Gallery, 15.9.2009 - 31.10.2009",Proud Flesh - Sally Mann,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Mann, Sally",119317796,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,15,9,2009,,31,10,2009,Vernissage,15,9,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Takashi Murakami, Gagosian Gallery, 17.9.2009 - 24.10.2009",Takashi Murakami,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Murakami, Takashi",122546334,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,17,9,2009,,24,10,2009,Vernissage,17,9,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Anselm Reyle - Monochrome Age, Gagosian Gallery, 17.9.2009 - 24.10.2009",Anselm Reyle - Monochrome Age,,,,,Einzelausstellung,Sonderausstellung,,,,,Objektkunst,4131740-3,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Reyle, Anselm",124607977,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,17,9,2009,,24,10,2009,Vernissage,17,9,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Objektkunst,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Go Figure: Richard Artschwager, Marcel Duchamp, Richard Hamilton, Jeff Koons, Roy Lichtenstein, Robert Mapplethorpe, László Moholy-Nagy, Carlo Mollino, Eadweard Muybridge, Sigmar Polke, Richard Prince, Man Ray, Gerhard Richter, James Rosenquist, Andy Warhol, Gagosian Gallery, 9.5.2009 - 13.6.2009",Go Figure,"Richard Artschwager, Marcel Duchamp, Richard Hamilton, Jeff Koons, Roy Lichtenstein, Robert Mapplethorpe, László Moholy-Nagy, Carlo Mollino, Eadweard Muybridge, Sigmar Polke, Richard Prince, Man Ray, Gerhard Richter, James Rosenquist, Andy Warhol",6530279-5,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,4037220-0,Fotografie,4045895-7,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Artschwager, Richard",118848127,Künstler:in,,"Duchamp, Marcel",11852772X,Künstler:in,"Hamilton, Richard",Künstler:in,"Koons, Jeff",Künstler:in,"Lichtenstein, Roy",Künstler:in,"Mapplethorpe, Robert",Künstler:in,"Moholy-Nagy, László",Künstler:in,"Mollino, Carlo",Künstler:in,"Muybridge, Eadweard",Künstler:in,"Polke, Sigmar",Künstler:in,"Prince, Richard",Künstler:in,"Ray, Man",Künstler:in,"Richter, Gerhard",Künstler:in,"Rosenquist, James",Künstler:in,"Warhol, Andy",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,5,2009,,13,6,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,Fotografie,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Cathedral of the Pines: Gregory Crewdson, Gagosian Gallery, 28.1.2016 - 5.3.2016",Cathedral of the Pines,Gregory Crewdson,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Crewdson, Gegory",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,28,1,2016,,5,3,2016,Vernissage,28,1,2016,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Michael Heizer - Altars, Gagosian Gallery, 9.5.2015 - 2.7.2015",Michael Heizer - Altars,,,,,Einzelausstellung,Sonderausstellung,,,,,Objektkunst,4131740-3,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Heizer, Michael",119112531,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,5,2015,,2,7,2015,Vernissage,9,5,2015,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Objektkunst,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"phantom - douglas gordon, Gagosian Gallery, 11.12.2014 - 17.1.2015",phantom - douglas gordon,,,,,Einzelausstellung,Sonderausstellung,,,,,Medienkunst,4113418-7,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,Park & 75,,,,,,,,,,,"Gordon, Douglas",120994011,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,12,2014,,17,1,2015,Vernissage,11,12,2014,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Medienkunst,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Takashi Murakami - In the Land of the Dead, Stepping on the Tail of a Rainbow, Gagosian Gallery, 10.11.2014 - 17.1.2015","Takashi Murakami - In the Land of the Dead, Stepping on the Tail of a Rainbow",,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Murakami, Takashi",122546334,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,11,2014,,17,1,2015,Vernissage,10,11,2014,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Paperwork and the Will of Capital: Taryn Simon, Gagosian Gallery, 18.2.2016 - 26.3.2016",Paperwork and the Will of Capital,Taryn Simon,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Simon, Taryn",129771953,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,18,2,2016,,26,3,2016,Vernissage,18,2,2016,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Richard Artschwager - No More Running Man, Gagosian Gallery, 9.1.2014 - 22.2.2014",Richard Artschwager - No More Running Man,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Artschwager, Richard",118848127,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,1,2014,,22,2,2014,Vernissage,9,1,2014,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Richard Serra - Solids, Gagosian Gallery, 3.11.2008 - 20.12.2008",Richard Serra - Solids,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Serra, Richard",118796267,Bildhauer:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,11,2008,,20,12,2008,Vernissage,2,11,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Elisa Sighicelli - The Party is Over, Gagosian Gallery, 14.1.2010 - 27.2.2010",Elisa Sighicelli - The Party is Over,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Sighicelli, Elisa",12340018X,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,1,2010,,27,2,2010,Vernissage,14,1,2010,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Roger Ballen - Boarding House, Gagosian Gallery, 5.11.2009 - 23.12.2009",Roger Ballen - Boarding House,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Ballen, Roger",119280736,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,11,2009,,23,12,2009,Vernissage,5,11,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Chamberlain Prouvé, Gagosian Gallery, 27.2.2015 - 4.4.2015",Chamberlain Prouvé,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Chamberlain, John",118669044,Bildhauer:in,,"Prouvé, Jean",118742043,Bildhauer:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,Galerie Patrick Seguin,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,27,2,2015,,4,4,2015,Vernissage,3,3,2015,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"David Smith - The Forgings, Gagosian Gallery, 29.10.2013 - 21.12.2013",David Smith - The Forgings,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Smith, David",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,29,10,2013,,21,12,2013,Vernissage,29,10,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Helen Frankenthaler - Composing with Color: Paintings 1962-1963, Gagosian Gallery, 11.9.2014 - 18.10.2014",Helen Frankenthaler - Composing with Color: Paintings 1962-1963,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Frankenthaler, Helen",119163926,Künstler:in,,"Elderfield, John",104959486X,Kurator:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,9,2014,,18,10,2014,Vernissage,11,9,2014,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Walter De Maria, Gagosian Gallery, 8.11.2014 - 20.12.2014",Walter De Maria,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,1228235120,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"De Maria, Walter",11890731X,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,The Estate of Walter De Maria,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,8,11,2014,,20,12,2014,Vernissage,8,11,2014,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"From Memory - Howard Hodgkin, Gagosian Gallery, 5.5.2016 - 18.6.2016",From Memory - Howard Hodgkin,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Hodgkin, Howard",118746774,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,5,2016,,18,6,2016,Vernissage,5,5,2016,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Mark Grotjahn, Gagosian Gallery, 13.9.2012 - 27.10.2012",Mark Grotjahn,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Grotjahn, Mark",128672803,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,9,2012,,27,10,2012,Vernissage,13,9,2012,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Robert Ryman - Untitled: A Painting in Four Parts, Gagosian Gallery, 30.7.2012 - 24.8.2012",Robert Ryman - Untitled,A Painting in Four Parts,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Ryman, Robert",119191776,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,30,7,2012,,24,8,2012,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Bruce Nauman - One Hundred Fish Fountain, Gagosian Gallery, 30.7.2012 - 24.8.2012",Bruce Nauman - One Hundred Fish Fountain,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,1228235120,Objektkunst,4131740-3,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Nauman, Bruce",118586610,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,30,7,2012,,24,8,2012,Vernissage,30,7,2012,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,Objektkunst,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"William Eggleston - At Zenith, Gagosian Gallery, 26.10.2013 - 21.12.2013",William Eggleston - At Zenith,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Eggleston, William",119015854,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,26,10,2013,,21,12,2013,Vernissage,26,10,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Ed Ruscha - Prints and Photographs, Gagosian Gallery, 8.5.2014 - 14.6.2014",Ed Ruscha - Prints and Photographs,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Ruscha, Ed",119255588,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,5,2014,,14,6,2014,Vernissage,8,5,2014,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Revisionism: Thirty New Works by Bob Dylan, Gagosian Gallery, 28.11.2012 - 12.1.2013",Revisionism: Thirty New Works by Bob Dylan,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Dylan, Bob",118528408,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,28,11,2012,,12,1,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Jeff Koons - New Paintings and Sculpture, Gagosian Gallery, 9.5.2013 - 29.6.2013",Jeff Koons - New Paintings and Sculpture,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,Plastik,4046277-8,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Koons, Jeff",119082292,Maler:in,Bildhauer:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,5,2013,,29,6,2013,Vernissage,9,5,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,Plastik,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Cy Twombly, Gagosian Gallery, 23.4.2015 - 20.6.2015",Cy Twombly,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Twombly, Cy",118624865,Bildhauer:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,23,4,2015,,20,6,2015,Vernissage,23,4,2015,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Brice Marden - Red, Yellow, Blue, Gagosian Gallery, 17.1.2013 - 23.2.2013","Brice Marden - Red, Yellow, Blue",,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Marden, Brice",119000849,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,17,1,2013,,23,2,2013,Vernissage,17,1,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Portraits of America: Diane Arbus, Cady Noland, Gagosian Gallery, 7.2.2014 - 19.4.2014",Portraits of America,"Diane Arbus, Cady Noland",,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,Plastik,4046277-8,Installation,1228235120,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Arbus, Diane",118745905,Künstler:in,,"Noland, Cady",120741075,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,2,2014,,19,4,2014,Vernissage,6,3,2014,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,Plastik,Installation,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Balthus - The Last Studies, Gagosian Gallery, 26.9.2013 - 21.12.2013",Balthus - The Last Studies,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,Balthus,118506331,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,26,9,2013,,21,12,2013,Vernissage,25,9,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Andreas Gursky, Gagosian Gallery, 4.11.2011 - 17.12.2011",Andreas Gursky,,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,4021845-4,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Gursky, Andreas",118940805,Grafiker:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,4,11,2011,,17,12,2011,Vernissage,4,11,2011,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Picasso & the Camera, Gagosian Gallery, 28.10.2014 - 3.1.2015",Picasso & the Camera,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Richardson, John",,Kurator:in,,"Picasso, Pablo",118594206,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,28,10,2014,,3,1,2015,Vernissage,28,10,2014,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Richard Prince, Gagosian Gallery, 8.5.2014 - 14.6.2014",Richard Prince,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Prince, Richard",11909987X,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,5,2014,,14,6,2014,Vernissage,8,5,2014,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Takashi Murakami - Tranquility of the Heart, Torment of the Flesh - Open Wide the Eye of the Heart, and Nothing is Invisible, Gagosian Gallery, 1.5.2007 - 9.6.2007","Takashi Murakami - Tranquility of the Heart, Torment of the Flesh - Open Wide the Eye of the Heart, and Nothing is Invisible",,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Murakami, Takashi",122546334,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,1,5,2007,,9,6,2007,Vernissage,1,5,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Manzoni - A Retrospective, Gagosian Gallery, 24.1.2009 - 21.3.2009",Manzoni - A Retrospective,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Celant, Germano",124431046,Kurator:in,,"Manzoni, Piero",118730754,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,"Archivio Opera Piero Manzoni, Milan",,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,24,1,2009,,21,3,2009,Vernissage,23,1,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Willem de Kooning - The Last Beginning, Gagosian Gallery, 18.9.2007 - 27.10.2007",Willem de Kooning - The Last Beginning,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Kertess, Klaus",113655924,Kurator:in,,"De Kooning, Willem",118713981,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,Johanna Liesbeth de Kooning Trust,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,18,9,2007,,27,10,2007,Vernissage,18,9,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Georg Baselitz - Remix Paintings, Gagosian Gallery, 9.11.2007 - 22.12.2007",Georg Baselitz - Remix Paintings,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Baselitz, Georg",11850701X,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,11,2007,,22,12,2007,Vernissage,9,11,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +https://gagosian.com/exhibitions/2008/isabel-and-other-intimate-strangers/,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Isabel and Other Intimate Strangers: Portraits by Alberti Giacometti and Francis Bacon, Gagosian Gallery, 3.11.2008 - 13.12.2008",Isabel and Other Intimate Strangers,Portraits by Alberti Giacometti and Francis Bacon,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,Malerei,4037220-0,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Giacometti, Alberto",118539094,Künstler:in,,"Bacon, Francis",11850570X,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,11,2008,,13,12,2008,Vernissage,2,11,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,Malerei,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Hiroshi Sugimoto - 7 Days / 7 Nights, Gagosian Gallery, 6.11.2008 - 20.12.2008",Hiroshi Sugimoto - 7 Days / 7 Nights,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Sugimoto, Hiroshi",119225743,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,11,2008,,20,12,2008,Vernissage,6,11,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"David Smith - Sprays, Gagosian Gallery, 17.1.2008 - 23.2.2008",David Smith - Sprays,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Smith, David",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,17,1,2008,,23,2,2008,Vernissage,17,1,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Lichtenstein - Girls, Gagosian Gallery, 12.5.2008 - 28.6.2008",Lichtenstein - Girls,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Lichtenstein, Roy",118572636,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,12,5,2008,,28,6,2008,Vernissage,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Willem de Kooning - A Centennial Exhibition, Gagosian Gallery, 24.4.2004 - 19.6.2004",Willem de Kooning - A Centennial Exhibition,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"De Kooning, Willem",118713981,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,24,4,2004,,19,6,2004,Vernissage,24,4,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Cecily Brown, Gagosian Gallery, 20.9.2008 - 25.10.2008",Cecily Brown,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Brown, Cecily",122716353,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,20,9,2008,,25,10,2008,Vernissage,20,9,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Marc Newson, Gagosian Gallery, 25.1.2007 - 3.3.2007",Marc Newson,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,Objektkunst,4131740-3,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Newson, Marc",122189922,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,25,1,2007,,3,3,2007,Vernissage,25,1,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,Objektkunst,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Philip Taaffe, Gagosian Gallery, 15.2.2007 - 31.3.2007",Philip Taaffe,,6072164-9,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Taaffe, Philip",119427893,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,15,2,2007,,31,3,2007,Vernissage,15,2,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Glenn Brown, Gagosian Gallery, 3.5.2007 - 9.6.2007",Glenn Brown,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Brown, Glenn",122870778,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,5,2007,,9,6,2007,Vernissage,3,5,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Vera Lutter, Gagosian Gallery, 15.3.2007 - 21.4.2007",Vera Lutter,,6072820-6,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Lutter, Vera",122861558,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,15,3,2007,,21,4,2007,Vernissage,15,3,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Frank Stella - A Breakthrough in Absraction: Exotic Birds, Gagosian Gallery, 16.4.2004 - 5.6.2004",Frank Stella - A Breakthrough in Absraction,Exotic Birds,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Stella, Frank",118753398,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,16,4,2004,,5,6,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Retrospective, Gagosian Gallery, 20.6.2008 - 22.8.2008",Retrospective,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,Objektkunst,4131740-3,Installation,1228235120,Medienkunst,4113418-7,Grafik,4021845-4,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Gordon, Douglas",120994011,Künstler:in,,"Uklanski, Piotr",,Künstler:in,"Murakami, Takashi",Künstler:in,"Golia, Piero",Künstler:in,"Lichtenstein, Roy",Künstler:in,"Friedman, Tom",Künstler:in,"Kippenberger, Martin",Künstler:in,"Johns, Jasper",Künstler:in,"Hamilton, Richard",Künstler:in,"Ruscha, Ed",Künstler:in,"Warhol, Andy",Künstler:in,"Burden, Chris",Künstler:in,"Duchamp, Marcel",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,20,6,2008,,22,8,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,Objektkunst,Installation,Medienkunst,Grafik,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Mark Grotjahn - Dancing Black Butterflies, Gagosian Gallery, 26.2.2008 - 11.3.2008",Mark Grotjahn - Dancing Black Butterflies,,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,4021845-4,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Grotjahn, Mark",128672803,Grafiker:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,26,2,2008,,11,3,2008,Vernissage,26,2,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Cy Twombly - Blooming: A Scattering of Blossoms and Other Things, Gagosian Gallery, 8.11.2007 - 22.12.2007",Cy Twombly - Blooming: A Scattering of Blossoms and Other Things,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,11,2007,,22,12,2007,Vernissage,8,11,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Blair Thurman, Gagosian Gallery, 1.11.2014 - 20.12.2014",Blair Thurman,,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,Installation,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Thurman, Blair",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,1,11,2014,,20,12,2014,Vernissage,1,11,2014,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Bildhauerei,Installation,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Francesco Vezzoli - Sacrilego, Gagosian Gallery, 5.2.2011 - 12.3.2011",Francesco Vezzoli - Sacrilego,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Vezzoli, Francesco",,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,2,2011,,12,3,2011,Vernissage,5,2,2011,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Alec Soth - The Last Days of W., Gagosian Gallery, 20.1.2009 - 7.3.2009",Alec Soth - The Last Days of W.,,,,,Einzelausstellung,Sonderausstellung,,,,,Objektkunst,,Design,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Soth, Alec",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,20,1,2009,,7,3,2009,Vernissage,20,1,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Alberto Giacometti, Arshile Gorky, Pablo Picasso, Jackson Pollock, Mark Rothko, David Smith, Gagosian Gallery, 5.11.2009 - 23.12.2009","Alberto Giacometti, Arshile Gorky, Pablo Picasso, Jackson Pollock, Mark Rothko, David Smith",,,,,Gruppenausstellung,Sonderausstellung,,,,,Bildhauerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Giacometti, Alberto",,Künstler:in,,"Gorky, Arshile",,Künstler:in,"Picasso, Pablo",Künstler:in,"Pollock, Jackson",Künstler:in,"Rothko, Mark",Künstler:in,"Smith, David",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,11,2009,,23,12,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Richaed Artschwager, Gagosian Gallery, 5.4.2002 - 4.5.2002",Richaed Artschwager,,,,,Einzelausstellung,Sonderausstellung,,,,,Objektkunst,,Bildhauerei,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Artschwager, Richard",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,4,2002,,4,5,2002,Vernissage,5,4,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Objektkunst,Bildhauerei,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Dan Flavin, John Chamberlain - Sculptures, Gagosian Gallery","Dan Flavin, John Chamberlain - Sculptures",,,,,Gruppenausstellung,Sonderausstellung,,,,,Bildhauerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Flavin, Dan",,Künstler:in,,"Chamberlain, John",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,10,2003,,,11,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Bildhauerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Alec Soth, Roger Ballen - New Photographs, Gagosian Gallery, 4.6.2005 - 29.7.2005","Alec Soth, Roger Ballen - New Photographs",,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Soth, Alec",,Künstler:in,,"Ballen, Roger",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,4,6,2005,,29,7,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"David Smith, Alexander Calder - Large Scale Works, Gagosian Gallery, 22.1.2005 - 26.2.2005","David Smith, Alexander Calder - Large Scale Works",,,,,Gruppenausstellung,Sonderausstellung,,,,,Bildhauerei,,Malerei,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Smith, David",,Künstler:in,,"Calder, Alexander",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,22,1,2005,,26,2,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Bildhauerei,Malerei,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Mike Kelley - Day is Done, Gagosian Gallery, 11.11.2005 - 17.12.2005",Mike Kelley - Day is Done,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Kelley, Mike",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,11,2005,,17,12,2005,Vernissage,10,11,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Michael Craig-Martin: Eye of The Storm, Gagosian Gallery, 16.1.2003 - 15.2.2003",Michael Craig-Martin,Eye of The Storm,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Craig-Martin, Michael",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,16,1,2003,,15,2,2003,Vernissage,16,1,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Douglas Gordon - Play Dead, Gagosian Gallery, 22.2.2003 - 29.3.2003",Douglas Gordon - Play Dead,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,,Medienkunst,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Gordon, Douglas",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,22,2,2003,,29,3,2003,Vernissage,22,2,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,Medienkunst,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Franz West - Sisyphos: Litter & Waste, Gagosian Gallery, 22.2.2003 - 29.3.2003",Franz West - Sisyphos: Litter & Waste,,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"West, Franz",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,22,2,2003,,29,3,2003,Vernissage,22,2,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Bildhauerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Pino Pascali, Gagosian Gallery, 1.2.2006 - 11.3.2006",Pino Pascali,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,,Objektkunst,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Pascali, Pino",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,1,2,2006,,11,3,2006,Vernissage,31,1,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,Objektkunst,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"John Currin, Gagosian Gallery, 11.11.2006 - 22.12.2006",John Currin,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Currin, John",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,11,2006,,22,12,2006,Vernissage,11,11,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Andy Warhol - Drawings and Related Works 1951-1986, Gagosian Gallery, 13.2.2003 - 22.3.2003",Andy Warhol - Drawings and Related Works 1951-1986,,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Warhol, Andy",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,2,2003,,22,3,2003,Vernissage,13,2,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Cecily Brown - Recent Paintings, Gagosian Gallery, 22.1.2005 - 26.2.2005",Cecily Brown - Recent Paintings,,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Brown, Cecily",,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,22,1,2005,,26,2,2005,Vernissage,22,1,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Cy Twombly - A Gathering of Time, Gagosian Gallery, 12.5.2003 - 12.7.2003",Cy Twombly - A Gathering of Time,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Twombly, Cy",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,12,5,2003,,12,7,2003,Vernissage,12,5,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Francesco Clemente - Paintings 2000-2003, Gagosian Gallery, 9.5.2003 - 21.6.2003",Francesco Clemente - Paintings 2000-2003,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Clemente, Francesco",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,5,2003,,21,6,2003,Vernissage,9,5,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Richard Artschwager, Gagosian Gallery, 24.1.2008 - 1.3.2008",Richard Artschwager,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,Objektkunst,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Artschwager, Richard",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,24,1,2008,,1,3,2008,Vernissage,24,1,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,Objektkunst,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Bruce Nauman - Animal Pyramid, Gagosian Gallery, 27.1.2015 - 21.2.2015",Bruce Nauman - Animal Pyramid,,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Nauman, Bruce",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,27,1,2015,,21,2,2015,Vernissage,27,1,2015,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Bildhauerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Warhol - Liz, Gagosian Gallery, 16.9.2011 - 22.10.2011",Warhol - Liz,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,Fotografie,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Warhol, Andy",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,16,9,2011,,22,10,2011,Vernissage,16,9,2011,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,Fotografie,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Richard Serra, Gagosian Gallery, 14.9.2011 - 26.11.2011",Richard Serra,,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,Installation,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Serra, Richard",,Bildhauer:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,9,2011,,26,11,2011,Vernissage,14,9,2011,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Bildhauerei,Installation,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Bob Dylan - The Asia Series, Gagosian Gallery, 20.9.2011 - 22.10.2011",Bob Dylan - The Asia Series,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Dylan, Bob",,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,20,9,2011,,22,10,2011,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Jenny Saville - Continuum, Gagosian Gallery, 15.9.2011 - 22.10.2011",Jenny Saville - Continuum,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Saville, Jenny",,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,15,9,2011,,22,10,2011,Vernissage,15,9,2011,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Jean Pigozzi - Johnny STOP!, Gagosian Gallery, 7.11.2010 - 23.12.2010",Jean Pigozzi - Johnny STOP!,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Pigozzi, Jean",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,11,2010,,23,12,2010,Vernissage,7,11,2010,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Georg Baselitz, Gagosian Gallery, 28.2.2012 - 7.4.2012",Georg Baselitz,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,Bildhauerei,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Baselitz, Georg",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,28,2,2012,,7,4,2012,Vernissage,28,2,2012,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,Bildhauerei,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Dennis Hopper - The Lost Album, Gagosian Gallery, 7.5.2013 - 22.6.2013",Dennis Hopper - The Lost Album,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,Installation,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Hopper, Dennis",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,5,2013,,22,6,2013,Vernissage,7,5,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,Installation,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Roy Lichtenstein - Still Lifes, Gagosian Gallery, 8.5.2010 - 30.7.2010",Roy Lichtenstein - Still Lifes,,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Lichtenstein, Roy",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,5,2010,,30,7,2010,Vernissage,8,5,2010,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Walter de Maria - 13, 14, 15 Meter Rows, Gagosian Gallery, 31.3.2007 - 5.5.2007","Walter de Maria - 13, 14, 15 Meter Rows",,,A Computer Which Will Solve Every Problem In The World / 3-12 Polygon,,Einzelausstellung,Sonderausstellung,,,,,Installation,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"De Maria, Walter",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,31,3,2007,,5,5,2007,Vernissage,31,3,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Claude Monet - Late Work, Gagosian Gallery, 1.5.2010 - 26.6.2010",Claude Monet - Late Work,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Monet, Claude",,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,1,5,2010,,26,6,2010,Vernissage,1,5,2010,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Anselm Kiefer - Morgenthau Plan, Gagosian Gallery, 3.5.2013 - 8.6.2013",Anselm Kiefer - Morgenthau Plan,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Kiefer, Anselm",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,5,2013,,8,6,2013,Vernissage,3,5,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Ed Ruscha - Books & Co., Gagosian Gallery, 5.3.2013 - 27.4.2013",Ed Ruscha - Books & Co.,,,,,Einzelausstellung,Sonderausstellung,,,,,Objektkunst,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Ruscha, Ed",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,3,2013,,27,4,2013,Vernissage,5,3,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Objektkunst,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Joel Morrison, Gagosian Gallery, 9.5.2011 - 25.6.2011",Joel Morrison,,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,Objektkunst,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Morrison, Joel",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,5,2011,,25,6,2011,Vernissage,9,5,2011,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Bildhauerei,Objektkunst,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Cecily Brown, Gagosian Gallery, 7.5.2013 - 22.6.2013",Cecily Brown,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Brown, Cecily",,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,5,2013,,22,6,2013,Vernissage,7,5,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Cecily Brown, Gagosian Gallery, 19.2.2002 - 16.3.2002",Cecily Brown,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Brown, Cecily",,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,19,2,2002,,16,3,2002,Vernissage,19,2,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Philip Taaffe - Works on Paper, Gagosian Gallery, 16.1.2010 - 20.2.2010",Philip Taaffe - Works on Paper,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Taaffe, Philip",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,16,1,2010,,20,2,2010,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Mark Tansey, Gagosian Gallery, 6.11.2004 - 18.12.2004",Mark Tansey,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Tansey, Mark",,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,11,2004,,18,12,2004,Vernissage,6,11,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Chris Burden, Gagosian Gallery, 20.1.2004 - 28.2.2004",Chris Burden,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Burden, Chris",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,20,1,2004,,28,2,2004,Vernissage,20,1,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Franz Gertsch, Gagosian Gallery, 20.1.2004 - 28.2.2004",Franz Gertsch,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Gertsch, Franz",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,"Collection Modern Art at the Pinakothek der Moderne, Munich",,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,20,1,2004,,28,2,2004,Vernissage,20,1,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Roger Ballen - Outland, Gagosian Gallery, 10.1.2002 - 16.2.2002",Roger Ballen - Outland,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Ballen, Roger",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,1,2002,,16,2,2002,Vernissage,10,1,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Elyn Zimmerman - New Drawings, Gagosian Gallery, 11.10.2001 - 10.11.2001",Elyn Zimmerman - New Drawings,,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Zimmerman, Elyn",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,10,2001,,10,11,2001,Vernissage,11,10,2001,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Monitor - Volume 2, Gagosian Gallery, 25.6.2002 - 9.8.2002",Monitor - Volume 2,,,,,Gruppenausstellung,Sonderausstellung,,,,,Medienkunst,,Installation,,Fotografie,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Abaroa, Eduardo",,Künstler:in,,"Ortiz, Rubén",,Künstler:in,"Courrèges, Francois-Xavier",Künstler:in,"Fast, Omer",Künstler:in,"Gispert, Luis",Künstler:in,"Gordon, Douglas",Künstler:in,"Jankowski, Christian",Künstler:in,"Melee, Robert",Künstler:in,"Ruilova, Aida",Künstler:in,"Staehle, Wolfgang",Künstler:in,"Tandberg, Vibeke",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,Sony ,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,25,6,2002,,9,8,2002,Vernissage,25,6,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Medienkunst,Installation,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Jeff Koons, Andy Warhol - Flower, Gagosian Gallery, 11.11.2002 - 21.12.2002","Jeff Koons, Andy Warhol - Flower",,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Warhol, Andy",,Künstler:in,,"Koons, Jeff",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,11,2002,,21,12,2002,Vernissage,11,11,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Andy Warhol - B&W Paintings: Ads and Illustrations, Gagosian Gallery, 2.3.2002 - 30.3.2002",Andy Warhol - B&W Paintings: Ads and Illustrations,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,Grafik,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Warhol, Andy",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,2,3,2002,,30,3,2002,Vernissage,1,3,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,Grafik,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"The Physical World: An Exhibition of Painting and Sculpture, Gagosian Gallery, 9.5.2002 - 29.6.2002",The Physical World,An Exhibition of Painting and Sculpture,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,,Bildhauerei,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Basquiat, Jean-Michel",,Künstler:in,,"Duchamp, Marcel",,Künstler:in,"Gober, Robert",Künstler:in,"Hirst, Damien",Künstler:in,"Johns, Jasper",Künstler:in,"Judd, Donald",Künstler:in,"Klein, Yves",Künstler:in,"Kline, Franz",Künstler:in,"Koons, Jeff",Künstler:in,"Newman, Barnett",Künstler:in,"Picasso, Pablo",Künstler:in,"Ryman, Robert",Künstler:in,"Saville, Jenny",Künstler:in,"Serra, Richard",Künstler:in,"Twombly, Cy",Künstler:in,"Warhol, Andy",Künstler:in,"Whiteread, Rachel",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,5,2002,,29,6,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,Bildhauerei,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Roy Lichtenstein - Landscapes in the Chinese Style, Gagosian Gallery, 1.3.2012 - 7.4.2012",Roy Lichtenstein - Landscapes in the Chinese Style,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Lichtenstein, Roy",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,1,3,2012,,7,4,2012,Vernissage,1,3,2012,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Willem de Kooning - Ten Paintings, 1983-1985, Gagosian Gallery, 8.11.2013 - 21.12.2013","Willem de Kooning - Ten Paintings, 1983-1985",,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"de Kooning, Willem",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,The Willem de Kooning Foundation,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,8,11,2013,,21,12,2013,Vernissage,8,11,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Avedon, Gagosian Gallery",Avedon,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Avedon, Richard",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Glenn Brown, Gagosian Gallery, 25.2.2004 - 10.4.2004",Glenn Brown,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Brown, Glenn",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,25,2,2004,,10,4,2004,Vernissage,24,2,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Georg Baselitz - The Turning Point: Paintings 1969-71: Recent Sculptures, Gagosian Gallery, 14.9.2004 - 30.10.2004",Georg Baselitz - The Turning Point: Paintings 1969-71,Recent Sculptures,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,Malerei,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Baselitz, Georg",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,9,2004,,30,10,2004,Vernissage,14,9,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Bildhauerei,Malerei,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Ellen Gallagher - exelento, Gagosian Gallery, 14.9.2004 - 23.10.2004",Ellen Gallagher - exelento,,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Gallagher, Ellen",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,9,2004,,23,10,2004,Vernissage,14,9,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Lepanto: Cy Twombly, Gagosian Gallery, 19.1.2002 - 23.2.2002",Lepanto,Cy Twombly,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Twombly, Cy",,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,19,1,2002,,23,2,2002,Vernissage,19,1,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Andy Warhol - Piss & Sex Paintings and Drawings, Gagosian Gallery, 19.9.2002 - 2.11.2002",Andy Warhol - Piss & Sex Paintings and Drawings,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Warhol, Andy",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,19,9,2002,,2,11,2002,Vernissage,19,9,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Richard Serra - Line Drawings, Gagosian Gallery, 14.9.2002 - 19.10.2002",Richard Serra - Line Drawings,,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Serra, Richard",,Bildhauer:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,9,2002,,19,10,2002,Vernissage,14,9,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Ferus, Gagosian Gallery, 12.9.2002 - 19.10.2002",Ferus,,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,,Fotografie,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Altoon, John",,Künstler:in,,"Bell, Larry",,Künstler:in,"Bengston, Billy Al",Künstler:in,"Berman, Wallace",Künstler:in,"Conner, Bruce",Künstler:in,"Cornell, Joseph",Künstler:in,"DeFeo, Jay",Künstler:in,"Diebenkorn, Richard",Künstler:in,"Irwin, Robert",Künstler:in,"Johns, Jasper",Künstler:in,"Judd, Donald",Künstler:in,"Kauffman, Craig",Künstler:in,"Kelly, Ellsworth",Künstler:in,"Kienholz, Ed",Künstler:in,"Lichtenstein, Roy",Künstler:in,"Moses, Ed",Künstler:in,"Price, Ken",Künstler:in,"Ruscha, Ed",Künstler:in,"Schwitters, Kurt",Künstler:in,"Smith, Hassel",Künstler:in,"Stella, Frank",Künstler:in,"Warhol, Andy",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,12,9,2002,,19,10,2002,Vernissage,12,9,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,Fotografie,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Anselm Kiefer - Merkaba, Gagosian Gallery, 8.11.2002 - 14.12.2002",Anselm Kiefer - Merkaba,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Kiefer, Anselm",,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,11,2002,,14,12,2002,Vernissage,8,11,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Richard Serra - Torqued Spirals, Toruses and Spheres, Gagosian Gallery, 18.10.2001 - 15.12.2001","Richard Serra - Torqued Spirals, Toruses and Spheres",,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,Installation,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Serra, Richard",,Bildhauer:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,18,10,2001,,15,12,2001,Vernissage,18,10,2001,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Bildhauerei,Installation,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Ed Ruscha - Paintings, Gagosian Gallery, 10.5.2002 - 15.6.2002",Ed Ruscha - Paintings,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Ruscha, Ed",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,5,2002,,15,6,2002,Vernissage,10,5,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"David Smith - Related Clues: Drawings, Paintings & Sculpture 1931-1964, Gagosian Gallery, 13.3.2004 - 17.4.2004",David Smith - Related Clues,"Drawings, Paintings & Sculpture 1931-1964",,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,Grafik,,Bildhauerei,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Smith, David",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,3,2004,,17,4,2004,Vernissage,12,3,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,Grafik,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Richard Wright, Gagosian Gallery, 26.1.2005 - 5.3.2005",Richard Wright,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Wright, Richard",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,26,1,2005,,5,3,2005,Vernissage,25,1,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Andy Warhol - Early Hand-painted Works, Gagosian Gallery, 22.9.2005 - 22.10.2005",Andy Warhol - Early Hand-painted Works,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Warhol, Andy",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,22,9,2005,,22,10,2005,Vernissage,22,9,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Roy Lichtenstein - Sculpture, Gagosian Gallery, 16.9.2005 - 22.10.2005",Roy Lichtenstein - Sculpture,,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Lichtenstein, Roy",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,16,9,2005,,22,10,2005,Vernissage,15,9,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Bildhauerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Jenny Saville - Migrants, Gagosian Gallery, 5.4.2003 - 3.5.2003",Jenny Saville - Migrants,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Saville, Jenny",,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,4,2003,,3,5,2003,Vernissage,5,4,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"David Smith - Personage, Gagosian Gallery, 10.3.2006 - 15.4.2006",David Smith - Personage,,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,Installation,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Smith, David",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,3,2006,,15,4,2006,Vernissage,10,3,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Bildhauerei,Installation,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"The Elusive Truth!: Damien Hirst - New Paintings, Gagosian Gallery, 11.3.2005 - 23.4.2005",The Elusive Truth!,Damien Hirst - New Paintings,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Hirst, Damien",,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,3,2005,,23,4,2005,Vernissage,11,3,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Martin Kippenberger - Lieber Maler Male Mir / Dear Painter Paint for me, Gagosian Gallery, 8.3.2005 - 23.4.2005",Martin Kippenberger - Lieber Maler Male Mir / Dear Painter Paint for me,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Kippenberger, Martin",,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,"The Estate of Martin Kippenberger, Cologne",,,Kooperationspartner:in,,,,,,,,,,,,,,,,,,,,,8,3,2005,,23,4,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Alec Soth - Niagara, Gagosian Gallery, 21.1.2006 - 25.2.2006",Alec Soth - Niagara,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Soth, Alec",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,21,1,2006,,25,2,2006,Vernissage,21,1,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Ghada Amer, Gagosian Gallery, 21.1.2006 - 25.2.2006",Ghada Amer,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Amer, Ghada",,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,21,1,2006,,25,2,2006,Vernissage,21,1,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Cy Twombly - Bacchus, Gagosian Gallery, 2.11.2005 - 24.12.2005",Cy Twombly - Bacchus,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Twombly, Cy",,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,2,11,2005,,24,12,2005,Vernissage,1,11,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Vera Lutter, Gagosian Gallery, 5.4.2003 - 3.5.2003",Vera Lutter,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Lutter, Vera",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,4,2003,,3,5,2003,Vernissage,5,4,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"The Sculptures of Pablo Picasso, Gagosian Gallery, 3.4.2003 - 3.5.2003",The Sculptures of Pablo Picasso,,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Picasso, Pablo",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,4,2003,,3,5,2003,Vernissage,3,4,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Bildhauerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Sally Mann, Gagosian Gallery, 16.3.2006 - 22.4.2006",Sally Mann,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Mann, Sally",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,16,3,2006,,22,4,2006,Vernissage,16,3,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Ed Ruscha - Drawings, Gagosian Gallery, 3.5.2006 - 10.6.2006",Ed Ruscha - Drawings,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Ruscha, Ed",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,5,2006,,10,6,2006,Vernissage,3,5,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Richard Serra - Rolled and Forged, Gagosian Gallery, 6.5.2006 - 11.8.2006",Richard Serra - Rolled and Forged,,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,Installation,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Serra, Richard",,Bildhauer:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,5,2006,,11,8,2006,Vernissage,5,5,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Bildhauerei,Installation,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Gagosian Gallery],"Blair Thurman, Gagosian Gallery, 1.11.2014 - 20.12.2014",Blair Thurman,,,,,Einzelausstellung,Sonderausstellung,,,,,Objektkunst,4131740-3,,,,,,,,,New York,4042011-5,,,,,,,Gagosian Gallery,1224078-3,,,,,,,,,,,,"Thurman, Blair",142575895,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gagosian Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,1,11,2014,,20,12,2014,Vernissage,1,11,2014,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Objektkunst,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"Jan De Cock, Museum of Modern Art, Society of Friends of Belgium in America",Jan De Cock,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,"De Cock, Jan",124779735,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,Society of Friends of Belgium in America,,,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,Vernissage,22,1,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"More Than One Photography, Museum of Modern Art",More Than One Photography,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,Banana Republic,,,Kooperationspartner:in,,,,,,,,,,,,,,,,,,,,,,5,2001,,,,,Vernissage,13,5,1992,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"Fashioning Fiction in Photography since 1990: Public Programs Spring 2004, Museum of Modern Art",Fashioning Fiction in Photography since 1990,Public Programs Spring 2004,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,Design,,,,,,,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,"Kismaric, Susan",,Kurator:in,,"Respini, Eva",,Kurator:in,"Barney, Tina",Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"The Armory Show 2002 - The International Fair of New Art, Museum of Modern Art, 22.2.2002 - 25.2.2002",The Armory Show 2002 - The International Fair of New Art,,,,,Gruppenausstellung,Sonderausstellung,,,The Armory Show - International Fair of New Art,,Fotografie,,Design,,Malerei,,Grafik,,Installation,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,"Kilimnik, Karen",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,22,2,2002,,25,2,2002,Vernissage,21,2,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"The Armory Show 2003, Museum of Modern Art, 6.3.2003 - 10.3.2003",The Armory Show 2003,,,,,Gruppenausstellung,Sonderausstellung,,,The Armory Show - International Fair of New Art,,Fotografie,,Design,,Malerei,,Grafik,,Installation,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,3,2003,,10,3,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"Comic Abstraction: Image-Breaking, Image-Making, Museum of Modern Art",Comic Abstraction,"Image-Breaking, Image-Making",,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,,Grafik,,Installation,,,,,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Vernissage,27,2,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"Projects 84: Josiah McElheny, Museum of Modern Art",Projects 84: Josiah McElheny,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,,,,,,,,,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,"McElheny, Josiah",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Vernissage,27,2,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"Helen Chadwick - Bad Blooms, Museum of Modern Art",Helen Chadwick - Bad Blooms,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,"Chadwick, Helen",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Vernissage,12,4,1995,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"Roy DeCarava - A Retrospective, Museum of Modern Art, 25.1.1996 - 7.5.1996",Roy DeCarava - A Retrospective,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,"DeCarava, Roy",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,25,1,1996,,7,5,1996,Vernissage,24,1,1996,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"New Photography Nine, Museum of Modern Art, 7.10.1993 - 4.1.1994",New Photography Nine,,,,,Gruppenausstellung,Sonderausstellung,,,Springs of Achievement Series on the Art of Photography,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,"Giglio, Christopher",,Fotograf:in,,"Mihailov, Boris",,Fotograf:in,"Steinmetz, Mark",Fotograf:in,"Streuli, Beat",Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,10,1993,,4,1,1994,Vernissage,5,10,1993,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"New Photography, Museum of Modern Art",New Photography,,,,,Gruppenausstellung,Sonderausstellung,,,"New Photography by Springs Induestries, Inc.",,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,"Sheer, Stephen A.",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,1991,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"New Photography, Museum of Modern Art",New Photography,,,,,Gruppenausstellung,Sonderausstellung,,,"New Photography by Springs Induestries, Inc.",,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,"Rupp, Sheron",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,1991,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"New Photography, Museum of Modern Art",New Photography,,,,,Gruppenausstellung,Sonderausstellung,,,"New Photography by Springs Induestries, Inc.",,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,"Grames, Eberhard",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,1991,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"New Photography, Museum of Modern Art, 20.10.1994 - 10.1.1995",New Photography,,,,,Gruppenausstellung,Sonderausstellung,,,"New Photography by Springs Induestries, Inc.",,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,"Rovner, Michal",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,20,10,1994,,10,1,1995,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"New Photography, Museum of Modern Art, 19.10.1995 - 6.1.1996",New Photography,,,,,Gruppenausstellung,Sonderausstellung,,,Springs of Achievement Series on the Art of Photography,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,"Barth, Uta",,Fotograf:in,,"Bartscherer, Joseph",,Fotograf:in,"Görlich, Ulrich",Fotograf:in,"Rondepierre, Eric",Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,19,10,1995,,6,1,1996,Vernissage,17,10,1995,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"Come Sunday - Photographs by Thomas Roma, Museum of Modern Art",Come Sunday - Photographs by Thomas Roma,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,"Roma, Thomas",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Vernissage,2,4,1996,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"Michael Schmidt U-NI-TY, Museum of Modern Art, 18.1.1996 - 26.3.1996",Michael Schmidt U-NI-TY,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,"Schmidt, Michael",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,Sprengel Museum Hannover,,,Kooperationspartner:in,,,,,,,,,,,,,,,,,,,,,18,1,1996,,26,3,1996,Vernissage,17,1,1996,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"New Photography, Museum of Modern Art",New Photography,,,,,Gruppenausstellung,Sonderausstellung,,,"New Photography by Springs Induestries, Inc.",,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,"Giglio, Christopher",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,1993,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"New Photography, Museum of Modern Art",New Photography,,,,,Gruppenausstellung,Sonderausstellung,,,"New Photography by Springs Induestries, Inc.",,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,"Steinmetz, Mark",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,1993,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"New Photography, Museum of Modern Art",New Photography,,,,,Gruppenausstellung,Sonderausstellung,,,"New Photography by Springs Induestries, Inc.",,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,"Mihailov, Boris",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,1993,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"New Photography, Museum of Modern Art",New Photography,,,,,Gruppenausstellung,Sonderausstellung,,,"New Photography by Springs Induestries, Inc.",,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,"Streuli, Beat",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,1993,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"Thomas Struth, Museum of Modern Art, 18.5.2003 - ..",Thomas Struth,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,"Struth, Thomas",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,Dallas Museum of Art,,,Kooperationspartner:in,,,,,,,,,,,,,,,,,,,,,18,5,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"John Szarkowski: Photographs, Museum of Modern Art, 21.1.2006 - ..",John Szarkowski: Photographs,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,"Szarkowski, John",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,San Francisco Museum of Modern Art,,,Kooperationspartner:in,,,,,,,,,,,,,,,,,,,,,21,1,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"projects 78: sabine hornig, Museum of Modern Art, 17.7.2003 - 8.9.2003",projects 78: sabine hornig,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,,,,,,,,,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,"Hornig, Sabine",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,17,7,2003,,8,9,2003,Vernissage,17,7,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"The Armory Show 2003 - The International Fair of New Art, Museum of Modern Art",The Armory Show 2003 - The International Fair of New Art,,,,,Einzelausstellung,Sonderausstellung,,,The Armory Show - International Fair of New Art,,Fotografie,,Design,,Malerei,,Grafik,,Installation,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,"Furnas, Barnaby",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Preview,6,3,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"Pictures of the Times: A Century of Photography from The New York , Museum of Modern Art, 27.6.1996 - 8.10.1996",Pictures of the Times: A Century of Photography from The New York ,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,American Museum of Natural History,The New York Public Library,The Pierpont Morgan Library,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,The New York Times,,,Kooperationspartner:in,American Museum of Natural History,Kooperationspartner:in,The New York Public Library,Kooperationspartner:in,The Pierpont Morgan Library,Kooperationspartner:in,,,,,,,,,,,,,,,27,6,1996,,8,10,1996,Vernissage,26,6,1996,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"The Armory Show 05 - The International Fair of New Art, Museum of Modern Art",The Armory Show 05 - The International Fair of New Art,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,Design,,Malerei,,Grafik,,Installation,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,"Nordström, Jockum",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Vernissage,10,3,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"Thomas Demand, Museum of Modern Art, 4.3.2005 - 30.3.2005",Thomas Demand,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,"Demand, Thomas",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,4,3,2005,,30,3,2005,Vernissage,2,3,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"The Armory Show 2003, Museum of Modern Art, 7.3.2003 - 10.3.2003",The Armory Show 2003,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,Design,,Malerei,,Grafik,,Installation,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,3,2003,,10,3,2003,Vernissage,6,3,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"To Benefit The Department of Prints and Illustrated Books of The Museum of Modern Art, Museum of Modern Art, 3.11.2005 - 6.11.2005",To Benefit The Department of Prints and Illustrated Books of The Museum of Modern Art,,,,,Gruppenausstellung,Sonderausstellung,,,15th annual ifpdaprintfair,,Grafik,,,,,,,,,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,"Smith, Kiki",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,11,2005,,6,11,2005,Vernissage,2,11,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"To Benefit The Department of Prints and Illustrated Books of The Museum of Modern Art, Museum of Modern Art, 4.11.2004 - 7.11.2004",To Benefit The Department of Prints and Illustrated Books of The Museum of Modern Art,,,,,Gruppenausstellung,Sonderausstellung,,,14th annual ifpdaprintfair,,Grafik,,,,,,,,,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,"Winters, Terry",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,4,11,2004,,7,11,2004,Vernissage,3,11,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"Andreas Gursky, Museum of Modern Art",Andreas Gursky,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,"Gursky, Andreas",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Vernissage,28,2,2001,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - MoMa],"Mount St. Helens: Photographs by Frank Gohlke, Museum of Modern Art, 29.6.2005 - 26.9.2005",Mount St. Helens: Photographs by Frank Gohlke,,,New Work/New Acquisitions,,Einzelausstellung,Sonderausstellung,Einzelausstellung,Sonderausstellung,,,Fotografie,,Installation,,Medienkunst,,,,,,New York,4042011-5,,,,,,,"The Museum of Modern Art (New York, NY)",1007559-8,,,,,,,,,,,,"Gohlke, Frank",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,The John Szarkowski Publications Fund,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,,,29,6,2005,,26,9,2005,Vernissage,28,6,2005,,29,6,2005,,26,9,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Tod Papageorge - American Sports 1970, Pace/MacGill Gallery, 11.6.2008 - 28.8.2008",Tod Papageorge - American Sports 1970,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Papageorge, Tod",132902982,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,6,2008,,28,8,2008,Vernissage,11,6,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Thomas Hoepker: Muhammad Ali, Pace/MacGill Gallery, 1.5.2004 - 29.5.2004",Thomas Hoepker: Muhammad Ali,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Höpker, Thomas",118631063,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,"Magnum Photos, Inc.",,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,1,5,2004,,29,5,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Chuck Close: Maquettes and Multi-Part Work (1966-2009), Pace/MacGill Gallery, 7.5.2009 - 6.6.2009",Chuck Close: Maquettes and Multi-Part Work (1966-2009),,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Close, Chuck",118871404,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,5,2009,,6,6,2009,Vernissage,6,4,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Adou, Pace/MacGill Gallery, 15.1.2009 - 14.2.2009",Adou,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,Adou,,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,15,1,2009,,14,2,2009,Vernissage,22,1,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"The Long Arm of Coincidence: Selections from the Rosalind and Melvin Jacobs Collection, Pace/MacGill Gallery, 2.4.2009 - 2.5.2009",The Long Arm of Coincidence,Selections from the Rosalind and Melvin Jacobs Collection,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,Rosalind and Melvin Jacobs Collection,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,2,4,2009,,2,5,2009,Vernissage,2,4,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"David Goldblatt - The Transported of KwaNdebele: A South African Odyssey, 1983-1984: Ex-Offenders at the Scene of Crime, 2008-2015, Pace/MacGill Gallery, 14.9.2016 - 29.10.2016","David Goldblatt - The Transported of KwaNdebele: A South African Odyssey, 1983-1984","Ex-Offenders at the Scene of Crime, 2008-2015",,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Goldblatt, David",122071131,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,9,2016,,29,10,2016,Vernissage,14,9,2016,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Snapshot Stories: From the Collection of Robert E. Jackson, Pace/MacGill Gallery, 20.6.2013 - 21.8.2013",Snapshot Stories,From the Collection of Robert E. Jackson,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Jackson, Robert E.",134170903,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,20,6,2013,,21,8,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Lee Friedlander - Nudes, Pace/MacGill Gallery, 26.10.2012 - 22.12.2012",Lee Friedlander - Nudes,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Friedlander, Lee",119292491,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,26,10,2012,,22,12,2012,Vernissage,27,10,2012,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Lee Friedlander - Mannequin, Pace/MacGill Gallery, 26.10.2012 - 22.12.2012",Lee Friedlander - Mannequin,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Friedlander, Lee",119292491,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,26,10,2012,,22,12,2012,Vernissage,27,10,2012,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Irving Penn - On Assignment, Pace/MacGill Gallery, 13.9.2013 - 26.10.2013",Irving Penn - On Assignment,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Penn, Irving",118739891,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,9,2013,,26,10,2013,Vernissage,12,9,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Judith Joy Ross - Protest The War, Pace/MacGill Gallery, 4.9.2008 - 11.10.2008",Judith Joy Ross - Protest The War,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Ross, Judith Joy",119368811,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,4,9,2008,,11,10,2008,Vernissage,10,9,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Ralf Schmerberg's Hommage A Noir, Pace/MacGill Gallery",Ralf Schmerberg's Hommage A Noir,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Schmerberg, Ralf",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,radical.media,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Vernissage,16,9,1999,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Fazal Sheikh - Portraits, Pace/MacGill Gallery, 8.12.1994 - 7.1.1995",Fazal Sheikh - Portraits,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Sheikh, Fazal",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,12,1994,,7,1,1995,Vernissage,8,12,1995,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Irving Penn - Present Concerns, Pace/MacGill Gallery, 29.1.2004 - 20.3.2004",Irving Penn - Present Concerns,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Penn, Irving",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,29,1,2004,,20,3,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Fazal Sheikh - Simpatia: Photographs of Brazil, Pace/MacGill Gallery, 5.9.2002 - 19.10.2002",Fazal Sheikh - Simpatia: Photographs of Brazil,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Sheikh, Fazal",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,9,2002,,19,10,2002,Vernissage,5,9,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Richard Misrach, Pace/MacGill Gallery, 15.1.2010 - 20.2.2010",Richard Misrach,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,Misrach. Richard,,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,15,1,2010,,20,2,2010,Vernissage,14,1,2010,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Richard Misrach - On the Beach 2.0, Pace/MacGill Gallery, 4.5.2013 - 29.6.2013",Richard Misrach - On the Beach 2.0,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,Misrach. Richard,,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,4,5,2013,,29,6,2013,Vernissage,3,5,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Joel Peter Witkin, Pace/MacGill Gallery, 23.3.1984 - 21.4.1984",Joel Peter Witkin,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Witkin, Joel Peter",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,23,3,1984,,21,4,1984,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Raghbir Singh - Photographs of India, Pace/MacGill Gallery, 17.10. - 16.11.",Raghbir Singh - Photographs of India,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Singh, Raghubir",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,17,10,,,16,11,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Looking Forward, Looking Back: An Exhibition to Honor 50 Years at the Pace Gallery, Pace/MacGill Gallery, 17.9. - 23.10.","Looking Forward, Looking Back",An Exhibition to Honor 50 Years at the Pace Gallery,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Frank, ?",,Künstler:in,,"Graham, ?",,Künstler:in,"Penn, ?",Künstler:in,"Sheeler, ?",Künstler:in,"Stieglitz, ?",Künstler:in,"Strand, ?",Künstler:in,"Weston, ?",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,17,9,,,23,10,,Vernissage,16,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Hai Bo, Pace/MacGill Gallery, 20.1. - 26.2.",Hai Bo,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Bo, Hai",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,20,1,,,26,2,,Vernissage,20,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"The Present, Pace/MacGill Gallery, 24.2.2012 - 24.3.2012",The Present,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Graham, Paul",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,24,2,2012,,24,3,2012,Vernissage,23,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Does Yellow Run Forever?, Pace/MacGill Gallery, 5.9.2014 - 4.10.2014",Does Yellow Run Forever?,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Graham, Paul",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,9,2014,,4,10,2014,Vernissage,4,9,2014,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Peter Hujar, Pace/MacGill Gallery, 28.2.2013 - 20.4.2013",Peter Hujar,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Hujar, Peter",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,28,2,2013,,20,4,2013,Vernissage,28,2,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Henry Wessel - Incidents, Pace/MacGill Gallery, 25.4.2013 - 15.6.2013",Henry Wessel - Incidents,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Wessel, Henry",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,25,4,2013,,15,6,2013,Vernissage,24,4,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Judith Joy Ross - The Devil Today and Reading to Dogs, Pace/MacGill Gallery, 8.12.2011 - 28.1.2012",Judith Joy Ross - The Devil Today and Reading to Dogs,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Ross, Judith Joy",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,12,2011,,28,1,2012,Vernissage,8,12,2012,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Lucas Samaras - Heads Chairs, Panoramas, Pace/MacGill Gallery, 13.1.1984 - 11.2.1984","Lucas Samaras - Heads Chairs, Panoramas",,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Samaras, Lucas",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,1,1984,,11,2,1984,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Mark Klett - Searching for Artifacts, Pace/MacGill Gallery, 17.2.1984 - 17.3.1984",Mark Klett - Searching for Artifacts,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Klett, Mark",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,17,2,1984,,17,3,1984,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"John Coplans, Pace/MacGill Gallery, 27.4. - 26.5.",John Coplans,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Coplans, John",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,27,4,,,26,5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Judith Joy Ross - Portraits, Pace/MacGill Gallery, 25.10.2002 - 30.11.2002",Judith Joy Ross - Portraits,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Ross, Judith Joy",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,25,10,2002,,30,11,2002,Vernissage,25,10,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Robert Frank - 27 photographs, Pace/MacGill Gallery, 27.10.1994 - 3.12.1994",Robert Frank - 27 photographs,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Frank, Robert",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,27,10,1994,,3,12,1994,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"William Wegman - Little Red Riding Hood & Letters, Numbers, Punctuation, Pace/MacGill Gallery, 28.10.1993 - 27.11.1993","William Wegman - Little Red Riding Hood & Letters, Numbers, Punctuation",,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Wegman, William",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,28,10,1993,,27,11,1993,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Emmet Gowin - Petra: in the Hashemite Kingdom of Jordan, Pace/MacGill Gallery",Emmet Gowin - Petra,in the Hashemite Kingdom of Jordan,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Gowin, Emmet",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Andre Kertesz - Distortions, Pace/MacGill Gallery, 5.11.1983 - 17.12.1983",Andre Kertesz - Distortions,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Kertesz, Andre",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,11,1983,,17,12,1983,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Chuck Close - Photographs, Pace/MacGill Gallery, 12.1. - 16.2.",Chuck Close - Photographs,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Close, Chuck",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,12,1,,,16,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"John Szarkowski - Photographs 1948-1962, Pace/MacGill Gallery, 15.9.1994 - 22.10.1994",John Szarkowski - Photographs 1948-1962,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Szarkowski, John",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,15,9,1994,,22,10,1994,Vernissage,20,9,1994,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Joel-Peter Witkin, Pace/MacGill Gallery, 11.3. - 24.4.",Joel-Peter Witkin,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Witkin, Joel Peter",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,3,,,24,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Harry Callahan - City Pictures, Pace/MacGill Gallery, 10.9. - 24.10.",Harry Callahan - City Pictures,,,Aaron Siskind - Divers,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Callahan, Harry",,Fotograf:in,,"Siskind, Aaron",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,9,,,24,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Mark Klett - Artifacts, Pace/MacGill Gallery, 19.10.1995 - 18.11.1995",Mark Klett - Artifacts,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Klett, Mark",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,19,10,1995,,18,11,1995,Vernissage,19,10,1995,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"William Wegman - Altered Photographs, Pace/MacGill Gallery, 19.10.1995 - 18.11.1995",William Wegman - Altered Photographs,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Wegman, William",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,19,10,1995,,18,11,1995,Vernissage,19,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Emmet Gowin - Petra, Pace/MacGill Gallery, 19.2. - 21.3.",Emmet Gowin - Petra,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Gowin, Emmet",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,19,2,,,21,3,,Vernissage,19,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Wanna See My Portfolio?, Pace/MacGill Gallery, 14.7. - 24.8.",Wanna See My Portfolio?,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Arbus, Diane",,Fotograf:in,,"Frank, Robert",,Fotograf:in,"Friedlander, Lee",Fotograf:in,"Michals, Dunae",Fotograf:in,"Rauschenberg, Robert",Fotograf:in,"Winogrand, Garry",Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,7,,,24,8,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Tono Stano - White Shadow, Pace/MacGill Gallery, 2.2.2012 - 17.3.2012",Tono Stano - White Shadow,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Stano, Tono",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,2,2,2012,,17,3,2012,Vernissage,2,2,2012,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Stephen Shore - Old and New, Pace/MacGill Gallery, 22.11.1995 - 6.1.1996",Stephen Shore - Old and New,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Shore, Stephen",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,22,11,1995,,6,1,1996,Vernissage,30,11,1995,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"John Szarkowski - Two Deserts and a Meadow, Pace/MacGill Gallery, 29.4.1999 - 12.6.1999",John Szarkowski - Two Deserts and a Meadow,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Szarkowski, John",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,29,4,1999,,12,6,1999,Vernissage,29,4,1999,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Dieter Appelt - Where No Memory Reaches, Pace/MacGill Gallery, 29.4.1999 - 12.6.1999",Dieter Appelt - Where No Memory Reaches,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Appelt, Dieter",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,29,4,1999,,12,6,1999,Vernissage,29,4,1999,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Chuck Close - Portraits and Nudes, Pace/MacGill Gallery, 16.3.2000 - 22.4.2000",Chuck Close - Portraits and Nudes,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Close, Chuck",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,16,3,2000,,22,4,2000,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Robert Rauschenberg, Pace/MacGill Gallery, 28.2. - 6.4.",Robert Rauschenberg,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,, ,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Rauschenberg, Robert",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,28,2,,,6,4,,Vernissage,28,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Robert Heinecken, Pace/MacGill Gallery, 28.2. - 6.4.",Robert Heinecken,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Heinecken, Robert",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,28,2,,,6,4,,Vernissage,28,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Harry Callahan and Emmet Gowin - eight by ten, Pace/MacGill Gallery, 6.12.2001 - 12.1.2002",Harry Callahan and Emmet Gowin - eight by ten,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Callahan, Harry",,Fotograf:in,,"Gowin, Emmet",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,12,2001,,12,1,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Joel Sternfeld - Walking the High Line, Pace/MacGill Gallery Chelsea, 13.11.2001 - 5.1.2002",Joel Sternfeld - Walking the High Line,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery Chelsea,3017805-8,,,,,,,,,,,,"Sternfeld, Joel",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery Chelsea,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,11,2001,,5,1,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Irving Penn - Still Life in Color 1947-2001, Pace/MacGill Gallery, 17.1.2002 - 23.2.2002",Irving Penn - Still Life in Color 1947-2001,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Penn, Irving",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,17,1,2002,,23,2,2002,Vernissage,17,1,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Robert Frank - Living Trust, Pace/MacGill Gallery, 15.1.2002 - 25.2.2002",Robert Frank - Living Trust,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Frank, Robert",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,15,1,2002,,25,2,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Dieter Appelt, Pace/MacGill Gallery, 5.9.2002 - 19.10.2002",Dieter Appelt,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Appelt, Dieter",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,9,2002,,19,10,2002,Vernissage,5,9,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Lauren Greenfield - Girl Culture, Pace/MacGill Gallery, 25.10.2002 - 30.11.2002",Lauren Greenfield - Girl Culture,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Greenfield, Lauren",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,25,10,2002,,30,11,2002,Vernissage,25,10,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Walker Evans - Duplicate Photographs from the Museum of Modern Art, Pace/MacGill Gallery, 5.12.2002 - 18.1.2003",Walker Evans - Duplicate Photographs from the Museum of Modern Art,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Evans, Walker",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,12,2002,,18,1,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"""Naked (sic) in the Landscape"", Pace/MacGill Gallery, 11.7.2002 - 28.8.2002","""Naked (sic) in the Landscape""",,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Appelt, Dieter",,Künstler:in,,"Arbus, Diane",,Künstler:in,"Bourdin, Guy",Künstler:in,"Brandt, Bill",Künstler:in,"Bullock, Wynn",Künstler:in,"Callahan, Harry",Künstler:in,"diCorcia, Philip-Lorca",Künstler:in,"Gowin, Emmet",Künstler:in,"Klett, Mark",Künstler:in,"Michals, Duane",Künstler:in,"Michener, Diana",Künstler:in,"Mikhailov, Boris",Künstler:in,"Minkkinen, Arno",Künstler:in,"Muniz, Vik",Künstler:in,"Rudolph, Glenn",Künstler:in,"Sternfeld, Joel",Künstler:in,"Wegman, William",Künstler:in,"Weston, Edward",Künstler:in,"Winogrand, Garry",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,7,2002,,28,8,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Walker Evans - Vintage Photographs from American Photographs and Fortune magazine, Pace/MacGill Gallery, 1.6.1984 - 4.7.1984",Walker Evans - Vintage Photographs from American Photographs and Fortune magazine,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Evans, Walker",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,1,6,1984,,4,7,1984,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Nicholas Nixon - Photographs 1985-1986, Pace/MacGill Gallery, 3.12. - 17.1.",Nicholas Nixon - Photographs 1985-1986,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Nixon, Nicholas",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,12,,,17,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Boris Mikhailov - The Insulted and the Injured, Pace/MacGill Gallery, 11.4.2002 - 11.5.2002",Boris Mikhailov - The Insulted and the Injured,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Mikhailov, Boris",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,4,2002,,11,5,2002,Vernissage,11,4,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Kiki Smith - Portraits, Pace/MacGill Gallery, 5.4.2001 - 5.5.2001",Kiki Smith - Portraits,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Smith, Kiki",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,4,2001,,5,5,2001,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Duane Michals - Who is Sidney Sherman?, Pace/MacGill Gallery, 25.10.2001 - 1.12.2001",Duane Michals - Who is Sidney Sherman?,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Michals, Duane",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,25,10,2001,,1,12,2001,Vernissage,25,10,2001,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"No Big Pictures - Summer Show 2001, Pace/MacGill Gallery, 5.7.2001 - 31.8.2001",No Big Pictures - Summer Show 2001,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Aaron, Peter",,Künstler:in,,"Acconci, Vito",,Künstler:in,"Appelt, Dieter",Künstler:in,"Arbus, Diane",Künstler:in,"Callahan, Harry",Künstler:in,"Christenberry, William",Künstler:in,"Close, Chuck",Künstler:in,"diCorcia, Philip-Lorca",Künstler:in,"Dine, Jim",Künstler:in,"Evans, Walker",Künstler:in,"Frank, Robert",Künstler:in,"Goldberg, Jim",Künstler:in,"Kertész, André",Künstler:in,"Kötting, Joey",Künstler:in,"Lartigue, Jacques-Henri",Künstler:in,"Michals, Duane",Künstler:in,"Michener, Diana",Künstler:in,"Outerbridge, Paul",Künstler:in,"Paulsen, Susan",Künstler:in,"Rexroth, Nancy",Künstler:in,"Ross, Judith Joy",Künstler:in,"Samaras, Lucas",Künstler:in,"Smith, Kiki",Künstler:in,"Warhol, Andy",Künstler:in,"Wegman, William",Künstler:in,"Witkin, Joel-Peter",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,7,2001,,31,8,2001,Vernissage,13,9,2001,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Guy Bourdin, Pace/MacGill Gallery, 6.9. - 20.10.",Guy Bourdin,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Bourdin, Guy",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,9,,,20,10,,Vernissage,6,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Gustave Le Gray, Pace/MacGill Gallery, 3.12. - 17.1.",Gustave Le Gray,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Le Gray, Gustave",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,12,,,17,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Social Media, Pace/MacGill Gallery, 16.9.2011 - 15.10.2011",Social Media,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Bartholl, Aram",,Künstler:in,,"Baker, Christopher",,Künstler:in,"Byrne, David",Künstler:in,"Harris, Jonathan",Künstler:in,"Heinecken, Robert",Künstler:in,"July, Miranda",Künstler:in,"Fletcher, Harrell",Künstler:in,"Kamvar, Sep",Künstler:in,"Umbrico, Penelope",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,16,9,2011,,15,10,2011,Vernissage,15,9,2011,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Pace/MacGill Gallery],"Mark Klett - Searching for Artifacts, Pace/MacGill Gallery, 17.2.1984 - 17.3.1984",Mark Klett - Searching for Artifacts,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Pace/MacGill Gallery,3017805-8,,,,,,,,,,,,"Klett, Mark",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Pace/MacGill Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,17,2,1984,,17,3,1984,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Deborah Bell],"summertime is children's time..., deborah bell photographs, 16.9.2005 - ..",summertime is children's time...,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,deborah bell photographs,,,,,,,,,,,,,"Albers, Josef",,Fotograf:in,,"Alveng, Dag",,Fotograf:in,"Bubley, Esther",Fotograf:in,"Cohen, John",Fotograf:in,"Fieret, G.P.",Fotograf:in,"Grazda, Edward",Fotograf:in,"Kaplan, Sid",Fotograf:in,"Levitt, Helen",Fotograf:in,"Paulsen, Susan",Fotograf:in,"Sander, August",Fotograf:in,"el Dowy, Gundula Schulze",Fotograf:in,"Winogrand, Garry",Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,deborah bell photographs,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,16,9,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Deborah Bell],"Sid Kaplan - 1950s to the present, deborah bell photographs, 22.9.2006 - 23.12.2006",Sid Kaplan - 1950s to the present,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,deborah bell photographs,,,,,,,,,,,,,"Kaplan, Sid",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,deborah bell photographs,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,22,9,2006,,23,12,2006,Vernissage,21,9,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Deborah Bell],"Susan Paulsen - Photographs, deborah bell photographs, 23.9.2005 - 29.10.2005",Susan Paulsen - Photographs,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,deborah bell photographs,,,,,,,,,,,,,"Paulsen, Susan",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,deborah bell photographs,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,23,9,2005,,29,10,2005,Vernissage,22,9,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Deborah Bell],"Gerard Petrus Fieret - Portraits from the 1960s & 1970s, deborah bell photographs, 8.5.2015 - 31.7.2015",Gerard Petrus Fieret - Portraits from the 1960s & 1970s,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,deborah bell photographs,,,,,,,,,,,,,"Fieret, Gerard Petrus",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,deborah bell photographs,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,5,2015,,31,7,2015,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Deborah Bell],"Artists See Artists - Portraits 1895-1979, deborah bell photographs, 7.6.2008 - 19.7.2008",Artists See Artists - Portraits 1895-1979,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,deborah bell photographs,,,,,,,,,,,,,"Maar, Dora",,Fotograf:in,,"Ray, Man",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,deborah bell photographs,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,6,2008,,19,7,2008,Vernissage,7,6,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Deborah Bell],"City Portraits, deborah bell photographs, 19.1.2008 - 5.4.2008",City Portraits,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,deborah bell photographs,,,,,,,,,,,,,"Faurer, Louis",,Fotograf:in,,"Levitt, Helen",,Fotograf:in,"Model, Lisette",Fotograf:in,"Sander, August",Fotograf:in,"Hujar, Peter",Fotograf:in,"Callahan, Harry",Fotograf:in,"Winogrand, Garry",Fotograf:in,"Arbus, Diane",Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,deborah bell photographs,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,19,1,2008,,5,4,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Deborah Bell],"Dag Alveng - Summer Light, deborah bell photographs, 13.9.2008 - 25.10.2008",Dag Alveng - Summer Light,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,deborah bell photographs,,,,,,,,,,,,,"Alveng, Dag",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,deborah bell photographs,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,9,2008,,25,10,2008,Vernissage,13,9,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Deborah Bell],"Garry Winogrand, deborah bell photographs, 8.9.2007 - 20.10.2007",Garry Winogrand,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,deborah bell photographs,,,,,,,,,,,,,"Winogrand, Garry",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,deborah bell photographs,Veranstalter,Collection of Eli Consilvio,Kooperationspartner,"Fraenkel Gallery, San Francisco",Kooperationspartner,,,,,,,,,,,,,,,,,,,,,8,9,2007,,20,10,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Deborah Bell],"Figure Studies, deborah bell photographs, 6.1.2009 - 28.2.2009",Figure Studies,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,deborah bell photographs,,,,,,,,,,,,,"Acconci, ?",,Fotograf:in,,"Blumenfeld, ?",,Fotograf:in,"Brandt, ?",Fotograf:in,"Faurer, ?",Fotograf:in,"Fieret, ?",Fotograf:in,"Hujar, ?",Fotograf:in,"Maar, ?",Fotograf:in,"Moriyama, ?",Fotograf:in,"Paulsen, ?",Fotograf:in,"Sander, ?",Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,deborah bell photographs,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,1,2009,,28,2,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Deborah Bell],"Susan Paulsen - New Color, deborah bell photographs, 30.10.2008 - 24.12.2008",Susan Paulsen - New Color,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,deborah bell photographs,,,,,,,,,,,,,"Paulsen, Susan",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,deborah bell photographs,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,30,10,2008,,24,12,2008,Vernissage,30,10,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Deborah Bell],"Andy Warhol's Street Diary - Photographs 1981-86, deborah bell photographs, 17.9.2010 - 13.11.2010",Andy Warhol's Street Diary - Photographs 1981-86,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,deborah bell photographs,,,,,,,,,,,,,"Warhol, Andy",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,deborah bell photographs,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,17,9,2010,,13,11,2010,Vernissage,16,9,2010,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Deborah Bell],"Close At Hand: Photographs by Mariana Cook, deborah bell photographs, 25.10.2007 - 28.12.2007",Close At Hand,Photographs by Mariana Cook,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,deborah bell photographs,,,,,,,,,,,,,"Cook, Mariana",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,deborah bell photographs,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,25,10,2007,,28,12,2007,Artist's Reception,24,10,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Structures and Surfaces - Poul Kjæerholm, Sean Kelly Gallery, R Gallery, 15.12.2007 - 2.2.2008",Structures and Surfaces - Poul Kjæerholm,,,,,Gruppenausstellung,Sonderausstellung,,,,,Medienkunst,4113418-7,Installation,1228235120,Objektkunst,4131740-3,Plastik,4046277-8,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,R Gallery,,,,,,,R & Company,,,,"Sheridan, Michael",1049597230,Kurator:in,,"Abramović, Marina",11908273X,Künstler:in,"de Barros, Geraldo",Künstler:in,"Calder, Alexander",Künstler:in,"Callahan, Harry",Künstler:in,"Celmins, Vija",Künstler:in,Gego,Künstler:in,"Gormley, Antony",Künstler:in,"Helmer-Petersen, Keld",Künstler:in,"Innes, Callum",Künstler:in,"Judd, Donald",Künstler:in,"Kelly, Ellsworth",Künstler:in,"Lawler, Louise",Künstler:in,"Lichtenstein, Roy",Künstler:in,"Mapplethorpe, Robert",Künstler:in,"Ray, Man",Künstler:in,"Richter, Gerhard",Künstler:in,"do Espírito Santo, Iran",Künstler:in,"Sugimoto, Hiroshi",Künstler:in,"Soulages, Pierre",Künstler:in,"Thiel, Frank",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,R Gallery,,,Veranstalter,,,,,,,,,,,,,R & Company,,,,,,,,15,12,2007,,2,2,2008,Vernissage,14,12,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Medienkunst,Installation,Objektkunst,Plastik,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Iran do Espirito Santo: Deposition, Sean Kelly Gallery, 5.9.2008 - 18.10.2008",Iran do Espirito Santo,Deposition,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,1228235120,,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Espírito Santo, Iran do",131804022,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,9,2008,,18,10,2008,Vernissage,4,9,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Anthony McCall - You and I, Horizontal (III), Sean Kelly Gallery, 2.2.2007 - 17.3.2007","Anthony McCall - You and I, Horizontal (III)",,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,1228235120,,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"McCall, Anthony",128584203,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,2,2,2007,,17,3,2007,Vernissage,1,2,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Primitivism Revisited, Sean Kelly Gallery, 16.12.2006 - 27.1.2007",Primitivism Revisited,,,,,Gruppenausstellung,Sonderausstellung,,,,,Objektkunst,4131740-3,Installation,1228235120,Medienkunst,4113418-7,Malerei,4037220-0,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,16,12,2006,,27,1,2007,Vernissage,15,12,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Objektkunst,Installation,Medienkunst,Malerei,,,Englisch,,,,,,,,,,, +https://www.skny.com/exhibitions/role-exchange,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Role Exchange: A Group Show, Sean Kelly Gallery, 29.6.2007 - 3.8.2007",Role Exchange,A Group Show,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Abramović, Marina",11908273X,Künstler:in,,"Anderson, Laurie",119296187,Künstler:in,"Antoni, Janine",Künstler:in,"Barney, Matthew",Künstler:in,"Calle, Sophie",Künstler:in,"Fosso, Samuel",Künstler:in,"Gober, Robert",Künstler:in,"Giocolea, Anthony",Künstler:in,"Gordon, Douglas",Künstler:in,"Greer, Fergus",Künstler:in,"Browery, Leigh",Künstler:in,"Grimonprez, Johan",Künstler:in,"Harris, Lyle Ashton",Künstler:in,"Leeson, Lynn Hershman",Künstler:in,"Journiac, Michel",Künstler:in,"Lee, Nikki",Künstler:in,"Linzy, Kalup",Künstler:in,"Lüthi, Urs",Künstler:in,"Mapplethorpe, Robert",Künstler:in,"Michals, Dunae",Künstler:in,"Morimura, Yasumasa",Künstler:in,"Morris, Robert",Künstler:in,"Piper, Adrian",Künstler:in,"Sherman, Cindy",Künstler:in,"Shonibare, Yinka",Künstler:in,"Turk, Gavin",Künstler:in,"Warhol, Andy",Künstler:in,"Wearing, Gillian",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,29,6,2007,,3,8,2007,Vernissage,28,6,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Robert Mapplethorpe - Certain People, Sean Kelly Gallery, 9.2.2008 - 15.3.2008",Robert Mapplethorpe - Certain People,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Mapplethorpe, Robert",118817019,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,2,2008,,15,3,2008,Vernissage,8,2,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Rebecca Horn - Cosmic Maps, Sean Kelly Gallery, 3.5.2008 - 14.6.2008",Rebecca Horn - Cosmic Maps,,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,4021845-4,Installation,1228235120,Objektkunst,4131740-3,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Horn, Rebecca",119066831,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,5,2008,,14,6,2008,Vernissage,2,5,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,Installation,Objektkunst,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Wolfgang Laib - Without Time - Without Body - Without Place, Sean Kelly Gallery, 7.9.2007 - 13.10.2007",Wolfgang Laib - Without Time - Without Body - Without Place,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,1228235120,,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Laib, Wolfgang",118568752,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,9,2007,,13,10,2007,Vernissage,6,9,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Los Carpinteros - La Montana Rusa, Sean Kelly Gallery, 22.3.2008 - 26.4.2008",Los Carpinteros - La Montana Rusa,,,,,Gruppenausstellung,Sonderausstellung,,,,,Objektkunst,4131740-3,Grafik,4021845-4,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,Los Carpinteros (Künstlervereinigung),4547660-3,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,22,3,2008,,26,4,2008,Vernissage,21,3,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Objektkunst,Grafik,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Marilyn: From Anastasi to Weegee, Sean Kelly Gallery, 11.6.2004 - 23.7.2004",Marilyn: From Anastasi to Weegee,,,,,Gruppenausstellung,Sonderausstellung,,,,,Grafik,4021845-4,,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Anastasi, William",122025172,Künstler:in,,"Coulis, Holly",138253099,Künstler:in,"Broodthaers, Marcel",Künstler:in,"Day, E. V.",Künstler:in,"de Dienes, Andre",Künstler:in,"Gordon, Douglos",Künstler:in,"Frank, Robert",Künstler:in,"Indiana, Robert",Künstler:in,"Haring, Keith",Künstler:in,"Johnson, Ray",Künstler:in,"Leonard, Zoe",Künstler:in,"Kruger, Barbara",Künstler:in,"Muniz, Vik",Künstler:in,"Morimura, Yasumasa",Künstler:in,"Pettibon, Raymond",Künstler:in,"Stern, Bert",Künstler:in,"Sherman, Cindy",Künstler:in,"Sullivan, Billy",Künstler:in,"Warhol, Andy",Künstler:in,"Villegle, Jacques",Künstler:in,Weegee,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,6,2004,,23,7,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Cancelled, Erased & Removed, Sean Kelly Gallery, 21.6.2008 - 1.8.2008","Cancelled, Erased & Removed",,,,,Gruppenausstellung,Sonderausstellung,,,,,Grafik,4021845-4,Objektkunst,4131740-3,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Antoni, Janine",121606996,Künstler:in,,"Azzarella, Josh",1112578269,Künstler:in,"Baldessari, John",Künstler:in,"Bidlo, Mike",Künstler:in,"Bradley, Slater",Künstler:in,"Gonzales-Torres, Felix",Künstler:in,"Gordon, Douglas",Künstler:in,"Holzer, Jenny",Künstler:in,"Hugonnier, Marine",Künstler:in,"Innes, Callum",Künstler:in,"Jaar, Alfredo",Künstler:in,"Kaphar, Titus",Künstler:in,"Khan, Idris",Künstler:in,"Klein, Yves",Künstler:in,"Kosuth, Joseph",Künstler:in,"Liversidge, Peter",Künstler:in,"Long, Richard",Künstler:in,"Macchi, Jorge",Künstler:in,"McCall, Anthony",Künstler:in,"Mendieta, Ana",Künstler:in,"Ruscha, Ed",Künstler:in,"Sarmento, Juliao",Künstler:in,"Teruya, Yuken",Künstler:in,"Turk, Gavin",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,21,6,2008,,1,8,2008,Vernissage,20,6,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,Objektkunst,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Wolfgang Laib - Frieze of Life, Sean Kelly Gallery, 30.10.2009 - 5.12.2009",Wolfgang Laib - Frieze of Life,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,1228235120,,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Laib, Wolfgang",118568752,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,30,10,2009,,5,12,2009,Vernissage,29,10,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Antony Gormley - Breathing Room II, Sean Kelly Gallery, 26.3.2010 - 1.5.2010",Antony Gormley - Breathing Room II,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,Installation,1228235120,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Gormley, Antony",119114348,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,26,3,2010,,1,5,2010,Vernissage,25,3,2010,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,Installation,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Ressonância, Resonance, Resonanz: Iran do Espírito Santo, Callum Innes, Wolfgang Laib, Sean Kelly Gallery, 13.12.2008 - 31.1.2009","Ressonância, Resonance, Resonanz","Iran do Espírito Santo, Callum Innes, Wolfgang Laib",,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,4037220-0,Objektkunst,4131740-3,Installation,1228235120,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Espírito Santo, Iran do",131804022,Künstler:in,,"Innes, Callum",119268523,Künstler:in,"Laib, Wolfgang",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,12,2008,,31,1,2009,Vernissage,12,12,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,Objektkunst,Installation,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Finnbogi Pétursson & Anthony McCall, Sean Kelly Gallery, 26.6.2009 - 31.7.2009",Finnbogi Pétursson & Anthony McCall,,,,,Gruppenausstellung,Sonderausstellung,,,,,Installation,1228235120,,,,,,,,,New York,4042011-5,Reykjavik,4049708-2,,,,,Sean Kelly Gallery,5532199-9,i8 Gallery,,,,,,,,,,,"McCall, Anthony",128584203,Künstler:in,,Finnbogi Pétursson,132272865,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,"i8 Gallery, Reykjavík",,,,,,,,,,,,,,,,,,,,,,,,26,6,2009,,31,7,2009,Vernissage,25,6,2009,,20,6,2009,,31,7,2009,Vernissage,19,6,2009,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Gavin Turk - Jazzz, Sean Kelly Gallery, 27.3.2009 - 2.5.2009",Gavin Turk - Jazzz,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,Objektkunst,4131740-3,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Turk, Gavin",119257793,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,27,3,2009,,2,5,2009,Vernissage,26,3,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,Objektkunst,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Julião Sarmento - House of Games, Sean Kelly Gallery, 18.9.2009 - 24.10.2009",Julião Sarmento - House of Games,,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,4021845-4,,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Sarmento, Juliao",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,18,9,2009,,24,10,2009,Vernissage,17,9,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Frank Thiel - New Work, Sean Kelly Gallery, 8.5.2009 - 20.6.2009",Frank Thiel - New Work,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Thiel, Frank",11924568X,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,5,2009,,20,6,2009,Vernissage,7,5,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Robert Mapplethorpe - Saints and Sinners, Sean Kelly Gallery, 14.12.2013 - 25.1.2014",Robert Mapplethorpe - Saints and Sinners,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Mapplethorpe, Robert",118817019,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,12,2013,,25,1,2014,Vernissage,13,12,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Slater Bradley - A Point Beyond the Tree, Sean Kelly Gallery, 14.12.2013 - 25.1.2014",Slater Bradley - A Point Beyond the Tree,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,Medienkunst,4113418-7,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Bradley, Slater",123817773,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,12,2013,,25,1,2014,Vernissage,13,12,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,Medienkunst,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Rebecca Horn - The Vertebrae Oracle, Sean Kelly Gallery, 10.5.2014 - 21.6.2014",Rebecca Horn - The Vertebrae Oracle,,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,4021845-4,Plastik,4046277-8,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Horn, Rebecca",119066831,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,5,2014,,21,6,2014,Vernissage,9,5,2014,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,Plastik,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Julião Sarmento - Terra Incognita, Sean Kelly Gallery, 28.3.2014 - 3.5.2014",Julião Sarmento - Terra Incognita,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,Grafik,4021845-4,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Sarmento, Juliao",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,28,3,2014,,3,5,2014,Vernissage,27,3,2014,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,Grafik,,,,,Englisch,,,,,,,,,,, +https://www.skny.com/exhibitions/pataphysics,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Pataphysiscs - A Theaoretical Exhibition, Sean Kelly Gallery, 13.9.2013 - 19.10.2013",Pataphysiscs - A Theaoretical Exhibition,,,,,Gruppenausstellung,Sonderausstellung,,,,,Plastik,4046277-8,Malerei,4037220-0,Grafik,4021845-4,Objektkunst,4131740-3,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Ai, Weiwei",129428205,Künstler:in,,"Bader, Darren",1015601200,Künstler:in,"Beuys, Joseph",Künstler:in,"Breuning, Olaf",Künstler:in,Los Carpinteros,Künstler:in,"Cattelan, Maurizio",Künstler:in,"Duchamp, Marcel",Künstler:in,"do Espirito Santo, Iran",Künstler:in,"Fischli, Peter",Künstler:in,"Weiss, David",Künstler:in,"Gilmore, Kate",Künstler:in,"Graham, Rodney",Künstler:in,"Grasso, Laurent",Künstler:in,"Hammons, David",Künstler:in,"Lincoln, Paul Etienne",Künstler:in,"Liversidge, Peter",Künstler:in,"Monk, Jonathan",Künstler:in,"Ono, Yoko",Künstler:in,"Ritchie, Matthew",Künstler:in,"Shrigley, David",Künstler:in,"Singh, Alexandre",Künstler:in,Slavs and Tatars,Künstler:in,"Strachan, Tavares",Künstler:in,"Téllez, Javier",Künstler:in,"Voigt, Jorinde",Künstler:in,"Youngman, Hennessy",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,Institute fr Creative Destruction,,,Kooperationspartner,International Neocronautical Society,Kooperationspartner,,,,,,,,,,,,,,,,,,,13,9,2013,,19,10,2013,Vernissage,12,9,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,Malerei,Grafik,Objektkunst,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"From Memory - Draw a Map of The United States, Sean Kelly Gallery, 13.9.2013 - 19.10.2013",From Memory - Draw a Map of The United States,,,,,Gruppenausstellung,Sonderausstellung,,,,,Grafik,4021845-4,,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Arakawa, Shūsaku",118503782,Künstler:in,,"Bark, Jed",,Künstler:in,"Bochner, Mel",Künstler:in,"Downey, Juan",Künstler:in,"Hay, Alex",Künstler:in,"Johns, Jasper",Künstler:in,"Kosuth, Joseph",Künstler:in,"Lew, Jeffrey",Künstler:in,"Logemann, Jane-Marie",Künstler:in,"Marden, Brice",Künstler:in,"Matta-Clark, Gordon",Künstler:in,"Nonas, Richard",Künstler:in,"Peterson, Robert",Künstler:in,"Rauschenberg, Robert",Künstler:in,"Rockburne, Dorothea",Künstler:in,"Rosenquist, James",Künstler:in,"Sonnier, Keith",Künstler:in,"Takahashi, Hisachika",Künstler:in,"Twombly, Cy",Künstler:in,"Weill, Susan",Künstler:in,"Weiner, Lawrence",Künstler:in,"Whitman, Robert",Künstler:in,"Wyma, Dan",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,9,2013,,19,10,2013,Vernissage,12,9,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Pure, Sean Kelly Gallery, 24.3. - 28.4.",Pure,,,,,Gruppenausstellung,Sonderausstellung,,,,,Grafik,,Malerei,,Konzeptkunst,,Installation,,Bildhauerei,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Abramović, Marina",,Künstler:in,,"Beuys, Joseph",,Künstler:in,"Bourgeois, Louise",Künstler:in,"Duchamp, Marcel",Künstler:in,"do Espírito Santo, Iran",Künstler:in,"Flavin, Dan",Künstler:in,"Fuss, Adam",Künstler:in,"Gillick, Liam",Künstler:in,"Gonzalez-Torres, Felix",Künstler:in,"Hodges, Jim",Künstler:in,"Holzer, Jenny",Künstler:in,"Horn, Roni",Künstler:in,"Houshiary, Shirazeh",Künstler:in,"Huws, Bethan",Künstler:in,"Innes, Callum",Künstler:in,"Kosuth, Joseph",Künstler:in,"Laib, Wolfgang",Künstler:in,"Lambri, Luisa",Künstler:in,"Levine, Sherrie",Künstler:in,"LeWitt, Sol",Künstler:in,"Long, Richard",Künstler:in,"Manzoni, Piero",Künstler:in,"Marioni, Joseph",Künstler:in,"Mapplethorpe, Robert",Künstler:in,"McBride, Rita",Künstler:in,"McCall, Anthony",Künstler:in,"Ryman, Robert",Künstler:in,"Sarmento, Juliao",Künstler:in,"Smith, Kiki",Künstler:in,"Sugimoto, Hiroshi",Künstler:in,"Thiel, Frank",Künstler:in,"Turk, Gavin",Künstler:in,"Whiteread, Rachel",Künstler:in,"Zimmerman, Jeff",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,24,3,,,28,4,,Vernissage,23,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Rebecca Horn - Twilight Transit, Sean Kelly Gallery, 28.10.2005 - 3.12.2005",Rebecca Horn - Twilight Transit,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,,,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Horn, Rebecca",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,28,10,2005,,3,12,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Callum Innes, Sean Kelly Gallery, 9.11. - ..",Callum Innes,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Innes, Callum",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,11,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Mapplethorpe - Neoclassicism, Sean Kelly Gallery, 1.7. - 12.8.",Mapplethorpe - Neoclassicism,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Mapplethorpe, Robert",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,1,7,,,12,8,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Gavin Turk - White Elephant, Sean Kelly Gallery, 4.2. - 5.3.",Gavin Turk - White Elephant,,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Turk, Gavin",,Bildhauer:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,4,2,,,5,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Bildhauerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Robert Mapplethorpe/Andy Warhol - Celebrity Portraits, Sean Kelly Gallery, 9.6. - 14.7.",Robert Mapplethorpe/Andy Warhol - Celebrity Portraits,,,Paolo Canevari - A Couple of Things I have to Tell You,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Mapplethorpe, Robert",,Fotograf:in,,"Warhol, Andy",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,6,,,14,7,,Vernissage,8,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Joseph Kosuth - Texts (Waiting for-) for Nothing': Samuel Beckett, in play, Sean Kelly Gallery",Joseph Kosuth - Texts (Waiting for-) for Nothing',"Samuel Beckett, in play",,,,Einzelausstellung,Sonderausstellung,,,,,Konzeptkunst,,,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Kosuth, Joseph",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Vernissage,29,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Konzeptkunst,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Robert Mapplethorpe - Saints and Sinners, Sean Kelly Gallery, 14.12.2013 - 25.1.2014",Robert Mapplethorpe - Saints and Sinners,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Mapplethorpe, Robert",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,12,2013,,25,1,2014,Vernissage,13,12,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Antony Gormley - Blind Light, Sean Kelly Gallery, 26.10.2007 - 1.12.2007",Antony Gormley - Blind Light,,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Gormley, Antony",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,26,10,2007,,1,12,2007,Vernissage,25,10,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Bildhauerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Laurent Grasso - Soleil Double, Sean Kelly Gallery, 13.9.2014 - 18.10.2014",Laurent Grasso - Soleil Double,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Grasso, Laurent",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,9,2014,,18,10,2014,Vernissage,12,9,2014,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Isabel Nolan - An Answer About the Sky, Sean Kelly Gallery, 13.9.2014 - 18.10.2014",Isabel Nolan - An Answer About the Sky,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,Textilkunst,,Bildhauerei,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Nolan, Isabel",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,9,2014,,18,10,2014,Vernissage,2,9,2014,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"James Casebere - The Levant, Sean Kelly Gallery, 5.5.2007 - 23.6.2007",James Casebere - The Levant,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Casebere, James",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,5,2007,,23,6,2007,Vernissage,4,5,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Los Carpinteros - Irreversible, Sean Kelly Gallery, 11.5.2013 - 22.6.2013",Los Carpinteros - Irreversible,,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,Los Carpinteros (Künstlervereinigung),,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,5,2013,,22,6,2013,Vernissage,11,5,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Bildhauerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Nathan Mabry - Shapeshifter, Sean Kelly Gallery, 29.3.2013 - 4.5.2013",Nathan Mabry - Shapeshifter,,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Mabry, Nathan",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,29,3,2013,,4,5,2013,Vernissage,28,3,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Bildhauerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Meshes of the Afternoon, Sean Kelly Gallery, 29.3.2013 - 4.5.2013",Meshes of the Afternoon,,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Brown, Cecily",,Künstler:in,,"Donachie, Kaye",,Künstler:in,"Elling, Lars",Künstler:in,"Falls, Sam",Künstler:in,"Favre, Valerie",Künstler:in,"Ksiazek, Pawel",Künstler:in,"Salle, David",Künstler:in,"Song, Lu",Künstler:in,"Zipp, Thomas",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,29,3,2013,,4,5,2013,Vernissage,28,3,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Callum Innes - Liminal, Sean Kelly Gallery, 25.10.2013 - 7.12.2013",Callum Innes - Liminal,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Innes, Callum",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,25,10,2013,,7,12,2013,Vernissage,24,10,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Birgir Andrésson, Poul Gernes - Bolt Out of the Blue, Sean Kelly Gallery, 24.6.2011 - 29.7.2011","Birgir Andrésson, Poul Gernes - Bolt Out of the Blue",,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,,Malerei,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Amdrésson, Birgir",,Künstler:in,,"Gernes, Poul",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,24,6,2011,,29,7,2011,Vernissage,23,6,2011,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Robert Mapplethorpe - 50 Americans, Sean Kelly Gallery, 7.5.2011 - 18.6.2011",Robert Mapplethorpe - 50 Americans,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Mapplethorpe, Robert",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,5,2011,,18,6,2011,Vernissage,6,5,2011,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"James Casebere - Selected Works 1995-2005, Sean Kelly Gallery, 25.10.2013 - 7.12.2013",James Casebere - Selected Works 1995-2005,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Casebere, James",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,25,10,2013,,7,12,2013,Vernissage,24,10,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Alec Soth - Broken Manual, Sean Kelly Gallery, 3.2.2012 - 11.3.2012",Alec Soth - Broken Manual,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Soth, Alec",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,2,2012,,11,3,2012,Vernissage,2,2,2012,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Anthony McCall - Leaving (with Two-Minute Silence), Sean Kelly Gallery, 11.12.2009 - 30.1.2010",Anthony McCall - Leaving (with Two-Minute Silence),,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,,Medienkunst,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"McCall, Anthony",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,12,2009,,30,1,2010,Vernissage,10,12,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Grafik,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sean Kelly],"Peter Liversidge - Where We Begon, Sean Kelly Gallery, 9.12.2011 - 28.1.2012",Peter Liversidge - Where We Begon,,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,Installation,,,,,,,,New York,4042011-5,,,,,,,Sean Kelly Gallery,5532199-9,,,,,,,,,,,,"Liversidge, Peter",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sean Kelly Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,12,2011,,28,1,2012,Vernissage,8,12,2011,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Zwirner & Wirth],"Dan Flavin - The 1964 Green Gallery Exhibition, Zwirner & Wirth, 6.3.2008 - 3.5.2008",Dan Flavin - The 1964 Green Gallery Exhibition,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,1228235120,,,,,,,,,New York,4042011-5,,,,,,,Zwirner & Wirth,,,,,,,,,,,,,"Flavin, Dan",118875736,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Zwirner & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,3,2008,,3,5,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Zwirner & Wirth],"Konrad Klapheck - Paintings, Zwirner & Wirth, 8.11.2007 - 22.12.2007",Konrad Klapheck - Paintings,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Zwirner & Wirth,,,,,,,,,,,,,"Klapheck, Konrad",118723340,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Zwirner & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,11,2007,,22,12,2007,Vernissage,7,11,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Zwirner & Wirth],"Alice Neel: Nudes of the 1930s, Zwirner & Wirth, David Zwirner, 6.5.2009 - 20.6.2009",Alice Neel: Nudes of the 1930s,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Zwirner & Wirth,,David Zwirner,,,,,,,,,,,"Neel, Alice",119286343,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Zwirner & Wirth,Veranstalter,David Zwirner,,,Veranstalter,,,,,,,,,,,,,,,,,,,,,6,5,2009,,20,6,2009,Vernissage,6,5,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Zwirner & Wirth],"Alice Neel: Selected Works, Zwirner & Wirth, David Zwirner, 14.5.2009 - 20.6.2009",Alice Neel: Selected Works,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Zwirner & Wirth,,David Zwirner,,,,,,,,,,,"Neel, Alice",119286343,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Zwirner & Wirth,Veranstalter,David Zwirner,,,Veranstalter,,,,,,,,,,,,,,,,,,,,,14,5,2009,,20,6,2009,Vernissage,14,5,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Zwirner & Wirth],"Franz West - Works from the 1990s, Zwirner & Wirth, 27.2.2009 - 25.4.2009",Franz West - Works from the 1990s,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Zwirner & Wirth,,,,,,,,,,,,,"West, Franz",119193744,Bildhauer:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Zwirner & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,27,2,2009,,25,4,2009,Vernissage,27,2,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Zwirner & Wirth],"H.C Westermann - Selected Work, Zwirner & Wirth, 13.9.2007 - 3.11.2007",H.C Westermann - Selected Work,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Zwirner & Wirth,,,,,,,,,,,,,"Westermann, H. C.",174288034,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Zwirner & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,9,2007,,3,11,2007,Vernissage,13,9,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Zwirner & Wirth],"Quiet Politics: Adel Abdessemed, Allora & Calzadilla, Michael Brown, Robert Gober, Felix Gonzalez-Torres, Roni Horn, Lisa Oppenheim, Walid Raad, Rosemarie Trockel, Christopher Williams, and others, Zwirner & Wirth, 26.6.2008 - 29.8.2008",Quiet Politics,"Adel Abdessemed, Allora & Calzadilla, Michael Brown, Robert Gober, Felix Gonzalez-Torres, Roni Horn, Lisa Oppenheim, Walid Raad, Rosemarie Trockel, Christopher Williams, and others",,,,Gruppenausstellung,Sonderausstellung,,,,,Grafik,4021845-4,Plastik,4046277-8,,,,,,,New York,4042011-5,,,,,,,Zwirner & Wirth,,,,,,,,,,,,,"Abdessemed, Adel",123044855,Künstler:in,,"Allora, Jennifer",129111678,Künstler:in,"Calzadilla, Guillermo ",Künstler:in,"Brown, Michael",Künstler:in,"Gober, Robert",Künstler:in,"Gonzalez-Torres, Felix",Künstler:in,"Horn, Roni",Künstler:in,"Oppenheim, Lisa",Künstler:in,"Raad, Walid",Künstler:in,"Trockel, Rosemarie",Künstler:in,"Williams, Christopher",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Zwirner & Wirth,Veranstalter,Allora & Calzadilla,16011392-1,,Künstlerkollektiv,,,,,,,,,,,,,,,,,,,,,26,6,2008,,29,8,2008,Vernissage,25,6,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,Plastik,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Zwirner & Wirth],"Works on Paper from the Collection of Helga and Walther Lauffs: Joseph Beuys, Mel Bochner, Hann Darboven, Eva Hesse, Jannis Kounellis, Claes Oldenburg, Zwirner & Wirth, 2.5.2008 - 21.6.2008",Works on Paper from the Collection of Helga and Walther Lauffs,"Joseph Beuys, Mel Bochner, Hann Darboven, Eva Hesse, Jannis Kounellis, Claes Oldenburg",,,,Gruppenausstellung,Sonderausstellung,,,,,Grafik,4021845-4,Malerei,4037220-0,,,,,,,New York,4042011-5,,,,,,,Zwirner & Wirth,,,,,,,,,,,,,"Beuys, Joseph",118510460,Künstler:in,,"Bochner, Mel",118922076,Künstler:in,"Darboven, Hanne",Künstler:in,"Hesse, Eva",Künstler:in,"Kounellis, Jannis",Künstler:in,"Oldenburg, Claes",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Zwirner & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,2,5,2008,,21,6,2008,Vernissage,14,5,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,Malerei,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Zwirner & Wirth],"Al Taylor - Early Work, Zwirner & Wirth, 9.1.2008 - 1.3.2008",Al Taylor - Early Work,,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,4021845-4,,,,,,,,,New York,4042011-5,,,,,,,Zwirner & Wirth,,,,,,,,,,,,,"Taylor, Al",121621790,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Zwirner & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,1,2008,,1,3,2008,Vernissage,9,1,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Zwirner & Wirth],"Conceptual Photography 1964-1989, Zwirner & Wirth, 9.5.2007 - 23.6.2007",Conceptual Photography 1964-1989,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Zwirner & Wirth,,,,,,,,,,,,,"Penone, Giuseppe",119236656,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Zwirner & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,5,2007,,23,6,2007,Vernissage,15,5,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Zwirner & Wirth],"Joseph Beuys - Sculpture and Drawing, Zwirner & Wirth",Joseph Beuys - Sculpture and Drawing,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Zwirner & Wirth,,,,,,,,,,,,,"Beuys, Joseph",118510460,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Zwirner & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,2,2007,,,3,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Zwirner & Wirth],"Fred Sandback - Early Work, Zwirner & Wirth, David Zwirner, 22.11.2006 - 6.1.2007",Fred Sandback - Early Work,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,1228235120,Plastik,4046277-8,,,,,,,New York,4042011-5,,,,,,,Zwirner & Wirth,,David Zwirner,,,,,,,,,,,"Sandback, Fred",119395940,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Zwirner & Wirth,Veranstalter,David Zwirner,,,Veranstalter,,,,,,,,,,,,,,,,,,,,,22,11,2006,,6,1,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,Plastik,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Zwirner & Wirth],"Fred Sandback - Large Scale Sculpture, Zwirner & Wirth, David Zwirner, 22.11.2006 - 22.12.2006",Fred Sandback - Large Scale Sculpture,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,1228235120,Plastik,4046277-8,,,,,,,New York,4042011-5,,,,,,,Zwirner & Wirth,,David Zwirner,,,,,,,,,,,"Sandback, Fred",119395940,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Zwirner & Wirth,Veranstalter,David Zwirner,,,Veranstalter,,,,,,,,,,,,,,,,,,,,,22,11,2006,,22,12,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,Plastik,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Zwirner & Wirth],"Blinky Palermo - The complete Prints and Multiples, Zwirner & Wirth, 5.4.2007 - 4.5.2007",Blinky Palermo - The complete Prints and Multiples,,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,,,,,,,,,,New York,4042011-5,,,,,,,Zwirner & Wirth,,,,,,,,,,,,,"Palermo, Blinky",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Zwirner & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,4,2007,,4,5,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Zwirner & Wirth],"Mary Heilmann - Some Pretty Colors, Zwirner & Wirth, 17.9.2008 - 25.10.2008",Mary Heilmann - Some Pretty Colors,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Zwirner & Wirth,,,,,,,,,,,,,"Heilmann, Mary",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Zwirner & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,17,9,2008,,25,10,2008,Vernissage,17,9,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Zwirner & Wirth],"Outdoor Sculpture, Zwirner & Wirth, 13.11.2007 - 27.1.2007",Outdoor Sculpture,,,,,Gruppenausstellung,Sonderausstellung,,,,,Bildhauerei,,,,,,,,,,New York,4042011-5,,,,,,,Zwirner & Wirth at David Zwirner,,,,,,,,,,,,,"Andre, Carl",,Künstler:in,,"Gober, Robert",,Künstler:in,"Lewitt, Sol",Künstler:in,"McCracken, John",Künstler:in,"Smith, Tony",Künstler:in,"di Suvero, Mark",Künstler:in,"West, Franz",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Zwirner & Wirth,Veranstalter,David Zwirner,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,,,13,11,2007,,27,1,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Zwirner & Wirth],"Claes Oldenburg - Early Work, Zwirner & Wirth, 29.10.2005 - 23.12.2005",Claes Oldenburg - Early Work,,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,,,,,,,,,New York,4042011-5,,,,,,,Zwirner & Wirth,,,,,,,,,,,,,"Oldenburg, Claes",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Zwirner & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,29,10,2005,,23,12,2005,Vernissage,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Zwirner & Wirth],"John McCracken - Early Sculpture, Zwirner & Wirth",John McCracken - Early Sculpture,,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,,,,,,,,,New York,4042011-5,,,,,,,Zwirner & Wirth,,,,,,,,,,,,,"McCracken, John",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Zwirner & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,9,2005,,,10,2005,Vernissage,9,9,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Zwirner & Wirth],"Diana Thater, Zwirner & Wirth, 7.1.2005 - 5.2.2005",Diana Thater,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,,Medienkunst,,,,,,,,New York,4042011-5,,,,,,,Zwirner & Wirth,,,,,,,,,,,,,"Thater, Diana",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Zwirner & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,1,2005,,5,2,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Zwirner & Wirth],"Gerhard Richter - Landscapes, Zwirner & Wirth, 4.5.2004 - 3.7.2004",Gerhard Richter - Landscapes,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Zwirner & Wirth,,,,,,,,,,,,,"Richter, Gerhard",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Zwirner & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,4,5,2004,,3,7,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Dan Flavin - Series and Progressions, David Zwirner, 5.11.2009 - 23.12.2009",Dan Flavin - Series and Progressions,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,1228235120,,,,,,,,,New York,4042011-5,,,,,,,"Zwirner, David","1,38E+08",,,,,,,,,,,,"Flavin, Dan",118875736,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,11,2009,,23,12,2009,Vernissage,5,11,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Yutaka Sone - It seems Like Snow Leopard Island, David Zwirner, 21.9.2006 - 21.10.2006",Yutaka Sone - It seems Like Snow Leopard Island,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Zwirner, David","1,38E+08",,,,,,,,,,,,"Sone, Yutaka",123044839,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,21,9,2006,,21,10,2006,Vernissage,21,9,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"a point in space is a place for an argument, David Zwirner, 28.6.2007 - 10.8.2007",a point in space is a place for an argument,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,Installation,1228235120,,,,,,,New York,4042011-5,,,,,,,"Zwirner, David","1,38E+08",,,,,,,,,,,,"Accola-Ruetz, Hans",125809352,Künstler:in,,"Bismuth, Julien",131505467,Künstler:in,"Bess, Forrest",Künstler:in,"Benglis, Lynda",Künstler:in,"Cadere, Andre",Künstler:in,"Chamberlain, John",Künstler:in,"De Keyser, Raoul",Künstler:in,"Fecteau, Vincent",Künstler:in,"Genzken, Isa",Künstler:in,"Heilmann, Mary",Künstler:in,"Hesse, Eva",Künstler:in,"Jensen, Alfred",Künstler:in,"Kelley, Mike",Künstler:in,"Khedoori, Rachel",Künstler:in,"Lozano, Lee",Künstler:in,"Mahalchik, Michael",Künstler:in,"Matta-Clark, Gordon",Künstler:in,"McCarthy, Paul",Künstler:in,"Nauman, Bruce",Künstler:in,"Oldenburg, Claes",Künstler:in,"Overstreet, Joe",Künstler:in,"Parrino, Steven",Künstler:in,"Rhoades, Jason",Künstler:in,"Roth, Dieter",Künstler:in,"Sandback, Fred",Künstler:in,"Schimert, Katy",Künstler:in,"de Saint Phalle, Niki",Künstler:in,"Taylor, Al",Künstler:in,"Thek, Paul",Künstler:in,"Wilkes, Cathy",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,28,6,2007,,10,8,2007,Vernissage,28,6,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,Installation,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Isa Genzken, David Zwirner, 16.9.2015 - 31.10.2015",Isa Genzken,,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,Malerei,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Genzken, Isa",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,16,9,2015,,31,10,2015,Vernissage,16,9,2015,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Wolfgang Tillmans - PCR, David Zwirner, 16.9.2015 - 24.10.2015",Wolfgang Tillmans - PCR,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,Installation,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Tillmans, Wolfgang",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,16,9,2015,,24,10,2015,Vernissage,16,9,2015,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Fred Sandback, David Zwirner",Fred Sandback,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,,,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Sandback, Fred",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,1,2009,,,2,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Proofs and Refutations, David Zwirner, 11.3.2011 - 30.4.2011",Proofs and Refutations,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,Malerei,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Ording, Philip",,Kurator:in,,"Whitney, Alexandra",,Kurator:in,"Alys, Francis",Künstler:in,"Brown, Trisha",Künstler:in,"Cadere, André",Künstler:in,VALIE EXPORT,Künstler:in,"Flynt, Henry",Künstler:in,"Forti, Simone",Künstler:in,"Graham, Dan",Künstler:in,"Herold, Georg",Künstler:in,"Jensen, Alfred",Künstler:in,"Lozano, Lee",Künstler:in,"Nauman, Bruce",Künstler:in,"Neuhaus, Max",Künstler:in,"Piper, Adrian",Künstler:in,"Polke, Sigmar",Künstler:in,"Quaytman, R. H.",Künstler:in,"Ray, Man",Künstler:in,"Rockburne, Dorothea",Künstler:in,"Taylor, Al",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,3,2011,,30,4,2011,Vernissage,11,3,2011,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Edward Kienholz - Roxys, David Zwirner, 6.5.2010 - 19.6.2010",Edward Kienholz - Roxys,,,,,Einzelausstellung,Sonderausstellung,,,,,Konzeptkunst,,Installation,,Objektkunst,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Kienholz, Edward",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,5,2010,,19,6,2010,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Thomas Ruff - New Work, David Zwirner, 9.3.2005 - 2.4.2005",Thomas Ruff - New Work,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Ruff, Thomas",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,3,2005,,2,4,2005,Vernissage,9,3,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"John McCracken, David Zwirner, 8.9.2006 - 14.10.2006",John McCracken,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,,,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"McCracken, John",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,9,2006,,14,10,2006,Vernissage,8,9,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Neo Rauch - Renegaten, David Zwirner, 9.5.2005 - 18.6.2005",Neo Rauch - Renegaten,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Rauch, Neo",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,5,2005,,18,6,2005,Vernissage,9,5,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Jockum Nordström, David Zwirner, 8.9.2006 - 14.10.2006",Jockum Nordström,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,Grafik,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Nordström, Jockum",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,9,2006,,14,10,2006,Vernissage,8,9,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Jason Rhoades, David Zwirner, 12.9.2003 - 25.10.2003",Jason Rhoades,,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,,,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Rhoades, Jason",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,12,9,2003,,25,10,2003,Vernissage,12,9,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Lisa Yuskavage - New Work, David Zwirner, 18.10.2006 - 18.11.2006",Lisa Yuskavage - New Work,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Yuskavage, Lisa",,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,18,10,2006,,18,11,2006,Vernissage,18,10,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Raoul De Keyser - Recent Work, David Zwirner, 18.10.2006 - 18.11.2006",Raoul De Keyser - Recent Work,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"De Keyser, Raoul",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,18,10,2006,,18,11,2006,Vernissage,18,10,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Katy Schimert, David Zwirner, 7.4.2006 - 6.5.2006",Katy Schimert,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Schimert, Katy",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,4,2006,,6,5,2006,Vernissage,7,4,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Michael Borremans - Horse Hunting, David Zwirner, 7.3.2006 - 1.4.2006",Michael Borremans - Horse Hunting,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Borremans, Michael",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,3,2006,,1,4,2006,Vernissage,7,3,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Christopher Williams, David Zwirner, 11.1.2006 - 25.2.2006",Christopher Williams,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Williams, Christopher",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,1,2006,,25,2,2006,Vernissage,11,1,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Luc Tuymans - Proper, David Zwirner, 14.10.2005 - 19.11.2005",Luc Tuymans - Proper,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Tuymans, Luc",,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,10,2005,,19,11,2005,Vernissage,14,10,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Michael S. Riedel - Neo, David Zwirner, 22.11.2005 - 23.12.2005",Michael S. Riedel - Neo,,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,,,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Riedel, Michael S.",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,22,11,2005,,23,12,2005,Vernissage,22,11,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Diana Thater, David Zwirner, 8.1.2005 - 5.2.2005",Diana Thater,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,,Medienkunst,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Thater, Diana",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,1,2005,,5,2,2005,Vernissage,7,1,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Rosa Loy - 9 Wege, David Zwirner, 27.6.2006 - 28.7.2006",Rosa Loy - 9 Wege,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Loy, Rosa",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,27,6,2006,,28,7,2006,Vernissage,27,6,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Stan Douglas - Cuba, David Zwirner, 22.10.2004 - 20.11.2004",Stan Douglas - Cuba,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Douglas, Stan",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,22,10,2004,,20,11,2004,Vernissage,22,10,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Raoul De Keyser - Remnants, David Zwirner, 1.11.2003 - 6.12.2003",Raoul De Keyser - Remnants,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"De Keyser, Raoul",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,1,11,2003,,6,12,2003,Vernissage,1,11,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Marcel Dzama - The Course of Human History Personified, David Zwirner, 8.9.2005 - 8.10.2005",Marcel Dzama - The Course of Human History Personified,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Dzama, Marcel",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,9,2005,,8,10,2005,Vernissage,8,9,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Raymond Pettibon, David Zwirner, 23.11.2004 - 24.12.2004",Raymond Pettibon,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei, ,,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Pettibon, Raymond",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,23,11,2004,,24,12,2004,Vernissage,23,11,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Isa Genzken - New Work, David Zwirner, 10.2.2005 - 5.3.2005",Isa Genzken - New Work,,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Genzken, Isa",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,2,2005,,5,3,2005,Vernissage,10,2,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Diana Thater, David Zwirner, 8.1.2005 - 5.2.2005",Diana Thater,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,,,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Thater, Diana",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,1,2005,,5,2,2005,Vernissage,7,1,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Early Work, David Zwirner, 29.6.2005 - 5.8.2005",Early Work,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Alys, Francis",,Künstler:in,,"De Keyser, Raoul",,Künstler:in,"Douglas, Stan",Künstler:in,"Genzken, Isa",Künstler:in,"Kawara, On",Künstler:in,"Matta-Clark, Gordon",Künstler:in,"Ofili, Chris",Künstler:in,"Pettibon, Raymonnd",Künstler:in,"Rauch, Neo",Künstler:in,"Rhoades, Jason",Künstler:in,"S. Riedel, MIchael",Künstler:in,"Ruff, Thomas",Künstler:in,"Schimert, Katy",Künstler:in,"Sone, Yutaka",Künstler:in,"Thater, Diana",Künstler:in,"Tuymans, Luc",Künstler:in,"Welling, James",Künstler:in,"Williams, Christopher",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,29,6,2005,,5,8,2005,Vernissage,29,6,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"James Welling - New Work, David Zwirner, 7.4.2005 - 7.5.2005",James Welling - New Work,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Welling, James",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,4,2005,,7,5,2005,Vernissage,7,4,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"John McCracken - New Sculpture, David Zwirner, 29.1.2004 - 28.2.2004",John McCracken - New Sculpture,,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"McCracken, John",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,29,1,2004,,28,2,2004,Vernissage,29,1,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Gordon Matta-Clark - Bingo and related works, David Zwirner, 10.4.2004 - 8.5.2004",Gordon Matta-Clark - Bingo and related works,,,,,Einzelausstellung,Sonderausstellung,,,,,Objektkunst,,Installation,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Matta-Clark, Gordon",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,4,2004,,8,5,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Yutaka Sone - Amusement Romana, David Zwirner, 6.3.2004 - 3.4.2004",Yutaka Sone - Amusement Romana,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,,,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Sone, Yutaka",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,3,2004,,3,4,2004,Vernissage,6,3,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"On Kawara - Paintings of 40 Years, David Zwirner, 9.9.2004 - 16.10.2004",On Kawara - Paintings of 40 Years,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Kawara, On",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,9,2004,,16,10,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Daniel Richter - The Morning After, David Zwirner, 10.5.2004 - 19.6.2004",Daniel Richter - The Morning After,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Richter, Daniel",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,5,2004,,19,6,2004,Vernissage,10,5,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Happy Days are Here Again, David Zwirner, 25.6.2004 - 30.7.2004",Happy Days are Here Again,,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,,Installation,,Bildhauerei,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Arocha, Carla",,Künstler:in,,"Bas, Hernan",,Künstler:in,"Brandenburg, Marc",Künstler:in,"Caivano, Ernesto",Künstler:in,"Clem, Chivas",Künstler:in,"Cline, Michael",Künstler:in,"Eder, Martin",Künstler:in,"Farquhar, Keith",Künstler:in,"Flamm, Christian",Künstler:in,"Gruzis, Evan",Künstler:in,"Holstad, Christian",Künstler:in,"Hopkins, Violet",Künstler:in,"Jensen, Sergej",Künstler:in,"Korty, David",Künstler:in,"Lowman, Nate",Künstler:in,"Loy, Rosa",Künstler:in,"Maggi, Marco",Künstler:in,"Masnyj, Yuri",Künstler:in,"Mauss, Nick",Künstler:in,"McEwen, Adam",Künstler:in,"Megerle, Birgit",Künstler:in,"P., Paul",Künstler:in,"Reeder, Tyson",Künstler:in,"Stauss, Peter",Künstler:in,"Vergueiro, Nicolau",Künstler:in,"von Wulffen, Amelie",Künstler:in,"Ziervogel, Ralf",Künstler:in,"Schlechtriem, André",Kurator:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,25,6,2004,,30,7,2004,Vernissage,25,6,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Fred Sandback - Decades: Works 1969-2000, David Zwirner, 9.3.2012 - 21.4.2012",Fred Sandback - Decades,Works 1969-2000,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,,,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Sandback, Fred",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,3,2012,,21,4,2012,Vernissage,3,2012,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - David Zwirner],"Donald Judd, David Zwirner, 6.5.2011 - 25.6.2011",Donald Judd,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,,Bildhauerei,,,,,,,,New York,4042011-5,,,,,,,David Zwirner,,,,,,,,,,,,,"Judd, Donald",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,David Zwirner,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,5,2011,,25,6,2011,Vernissage,6,5,2011,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Gutai, Hauser & Wirth, 1.11.2018 - 22.12.2018",Gutai,,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Maekawa, Tsuyoshi",1051779790,Künstler:in,,"Matsutani, Takesada",143955616,Künstler:in,"Motonaga, Sadamasa",Künstler:in,"Shimamoto, Shozo",Künstler:in,"Shiraga, Kazuo",Künstler:in,"Tanaka, Atsuko",Künstler:in,"Uemae, Chiyu",Künstler:in,"Yamazaki, Tsuruko",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,1,11,2018,,22,12,2018,Private View,1,11,2018,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Phyllida Barlow -Tilt, Hauser & Wirth, 14.11.2018 - 22.12.2018",Phyllida Barlow -Tilt,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Barlow, Phyllida",13894170X,Bildhauer:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,11,2018,,22,12,2018,Private View,14,11,2018,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Anna Maria Maiolino - Errância Poética (Poetic Wanderings), Hauser & Wirth, 14.11.2018 - 22.12.2018",Anna Maria Maiolino - Errância Poética (Poetic Wanderings),,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Maiolino, Anna Maria",130538981,Bildhauer:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,11,2018,,22,12,2018,Private View,14,11,2018,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"A Luta Continua - The Sylvio Perlstein Collection, Hauser & Wirth, 26.4.2018 - 27.7.2018",A Luta Continua - The Sylvio Perlstein Collection,,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,The Sylvio Perlstein Collection,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,26,4,2018,,27,7,2018,Private View,26,4,2018,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Eduardo Chillida, Hauser & Wirth, 30.4.2018 - 27.7.2018",Eduardo Chillida,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Chillida, Eduardo",11852044X,Bildhauer:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,30,4,2018,,27,7,2018,Private View,30,4,2018,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Mark Wallinger - Study for Self Reflection, Hauser & Wirth, 13.9.2018 - 27.10.2018",Mark Wallinger - Study for Self Reflection,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,1228235120,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Wallinger, Mark",119391899,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,9,2018,,27,10,2018,Private View,13,9,2018,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Arte Povera, Hauser & Wirth, 12.9.2017 - 28.10.2017",Arte Povera,,,,,Gruppenausstellung,Sonderausstellung,,,,,Installation,1228235120,Plastik,4046277-8,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Goetz, Ingvild",11914333X,Kurator:in,,"Abate, Cladio",,Künstler:in,"Anselmo, Giovanni",Künstler:in,"Boetti, Alighiero",Künstler:in,"Calzolari, Pier Paolo",Künstler:in,"Colombo, Giorgio",Künstler:in,"Fabro, Luciano",Künstler:in,"Kounellis, Jannis",Künstler:in,"Merz, Mario",Künstler:in,"Sartor, Paolo Mussat",Künstler:in,"Paolini, Giulio",Künstler:in,"Pascali, Pino",Künstler:in,"Penone, Giuseppe",Künstler:in,"Postoletto, Michelangelo",Künstler:in,"Prini, Emilio",Künstler:in,"Zorio, Gilberto",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,12,9,2017,,28,10,2017,Private View,12,9,2017,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,Plastik,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Mira Schendel - Sarrafos and Black and White Works, Hauser & Wirth, 7.9.2017 - 21.10.2017",Mira Schendel - Sarrafos and Black and White Works,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Schendel, Mira",118754564,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,9,2017,,21,10,2017,Private View,7,9,2017,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Books - Dieter Roth, Björn Roth: Studio, Hauser & Wirth, 27.4.2017 - 29.7.2017","Books - Dieter Roth, Björn Roth",Studio,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Roth, Dieter",118603086,Künstler:in,,"Roth, Björn",119180847,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,27,4,2017,,29,7,2017,Private View,27,4,2017,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Roni Horn, Hauser & Wirth, 27.4.2017 - 29.7.2017",Roni Horn,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Horn, Roni",118553658,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,27,4,2017,,29,7,2017,Private View,27,4,2017,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Phyllida Barlow - ... Later, Hauser & Wirth, 5.11.2012 - 22.12.2012",Phyllida Barlow - ... Later,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Barlow, Phyllida",13894170X,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,11,2012,,22,12,2012,Vernissage,5,11,2012,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Sensitive Geometries: Brazil 1950s - 1980s, Hauser & Wirth, 12.9.2013 - 26.10.2013",Sensitive Geometries,Brazil 1950s - 1980s,1049769384,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Renaud-Clément, Olivier",1136441522,Organisator:in,,"Charoux, Lothar",1049770137,Künstler:in,"Cordeiro, Waldemar",Künstler:in,"Costa, Joao José",Künstler:in,"de Barros, Geraldo",Künstler:in,"Fiaminghi, Hermelindo",Künstler:in,"Leal, Paulo Roberto",Künstler:in,"Ludolf, Rubem",Künstler:in,"Maiolino, Anna Maria",Künstler:in,"Schendel, Mira",Künstler:in,"Serpa, Ivan",Künstler:in,"Weissmann, Franz",Künstler:in,"Werneck, Paulo",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,12,9,2013,,26,10,2013,Private View,12,9,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Matthew Day Jackson - Something Ancient, Something New, Something Stolen, Something Blue, Hauser & Wirth, 6.9.2013 - 19.10.2013","Matthew Day Jackson - Something Ancient, Something New, Something Stolen, Something Blue",,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Jackson, Matthew Day",133845133,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,9,2013,,19,10,2013,Private View,6,9,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Freezer Burn, Hauser & Wirth, 8.11.2014 - 20.12.2014",Freezer Burn,,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,4037220-0,Grafik,4021845-4,Plastik,4046277-8,Installation,1228235120,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Ackermann, Rita",128576022,Organisator:in,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,11,2014,,20,12,2014,Private View,8,11,2014,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,Grafik,Plastik,Installation,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Thomas Houseago - Moun Room, Hauser & Wirth, 10.11.2014 - 17.1.2015",Thomas Houseago - Moun Room,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,1228235120,Plastik,4046277-8,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Houseago, Thomas",139434836,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,11,2014,,17,1,2015,Private View,10,11,2014,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,Plastik,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Anj Smith - The Flowering of Phantoms, Hauser & Wirth, 15.1.2013 - 23.2.2013",Anj Smith - The Flowering of Phantoms,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Smith, Anj",1022613375,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,15,1,2013,,23,2,2013,Private View,15,1,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Sterling Ruby - Sunrise Sunset, Hauser & Wirth, 9.5.2014 - 25.7.2014",Sterling Ruby - Sunrise Sunset,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Ruby, Sterling",13226871X,Bildhauer:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,5,2014,,25,7,2014,Private View,9,5,2014,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Anna Maria Maiolino - Between Senses, Hauser & Wirth, 7.5.2014 - 21.6.2014",Anna Maria Maiolino - Between Senses,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Maiolino, Anna Maria",130538981,Bildhauer:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,5,2014,,21,6,2014,Private View,7,5,2014,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Ida Applebroog - The Ethics of Desire, Hauser & Wirth, 14.5.2015 - 31.7.2015",Ida Applebroog - The Ethics of Desire,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,1228235120,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Applebroog, Ida",119018802,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,5,2015,,31,7,2015,Private View,14,5,2015,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Lee Lozano - Drawings & Paintings, Hauser & Wirth, 14.5.2015 - 31.7.2015",Lee Lozano - Drawings & Paintings,,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,4021845-4,Malerei,4037220-0,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Lozano, Lee",124023738,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,5,2015,,31,7,2015,Private View,14,5,2015,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,Malerei,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Leon Goulb - Riot, Hauser & Wirth, 11.5.2015 - 20.6.2015",Leon Goulb - Riot,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Golub, Leon",119328933,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,5,2015,,20,6,2015,Private View,11,5,2015,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Josephsohn, Hauser & Wirth, 15.1.2014 - 22.2.2014",Josephsohn,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Josephsohn, Hans",118558439,Bildhauer:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,15,1,2014,,22,2,2014,Private View,15,1,2014,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Ida Applebroog - Monalisa, Hauser & Wirth, 19.1.2010 - 6.3.2010",Ida Applebroog - Monalisa,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Applebroog, Ida",119018802,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,19,1,2010,,6,3,2010,Vernissage,19,1,2010,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +https://www.hauserwirth.com/hauser-wirth-exhibitions/3323-white-snow/,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Paul McCarthy - White Snow, Hauser & Wirth, 4.11.2009 - 24.12.2009",Paul McCarthy - White Snow,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"McCarthy, Paul",119555549,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,4,11,2009,,24,12,2009,Vernissage,4,11,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Re-View - Onnasch Collection, Hauser & Wirth, 7.2.2014 - 12.4.2014",Re-View - Onnasch Collection,,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,4037220-0,Objektkunst,4131740-3,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Schimmel, Paul",138740003,Kurator:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,2,2014,,12,4,2014,Private View,7,2,2014,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,Objektkunst,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Philip Guston - Painter 1957-1967, Hauser & Wirth, 26.4.2016 - 29.7.2016",Philip Guston - Painter 1957-1967,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Guston, Philip",119205637,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,26,4,2016,,29,7,2016,Private View,26,4,2016,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Serialities, Hauser & Wirth, 15.2.2017 - 8.4.2017",Serialities,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,Grafik,4021845-4,Plastik,4046277-8,Installation,1228235120,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Renaud-Clément, Olivier",1136441522,Organisator:in,,"Agematsu, Yuji",1133520928,Künstler:in,"Andre, Carl",Künstler:in,"Becher, Bernd",Künstler:in,"Becher, Hilla",Künstler:in,"Calle, Sophie",Künstler:in,"Deschenes, Liz",Künstler:in,"Genzken, Isa",Künstler:in,"Hesse, Eva",Künstler:in,"Horn, Roni",Künstler:in,"Kawara, On",Künstler:in,"Kinmont, Robert",Künstler:in,"Lawler, Louise",Künstler:in,"Leonard, Zoe",Künstler:in,"Levine, Sherrie",Künstler:in,"Lewitt, Sol",Künstler:in,"McCarthy, Paul",Künstler:in,"Opalka, Roman",Künstler:in,"Robbins, Andrea",Künstler:in,"Becher, Max",Künstler:in,"Sander, August",Künstler:in,"Sander, Karin",Künstler:in,"Schendel, Mira",Künstler:in,"Sherman, Cindy",Künstler:in,"Smith, David",Künstler:in,"Wallace, Ian",Künstler:in,"Wallinger, Mark",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,15,2,2017,,8,4,2017,Private View,15,2,2017,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,Grafik,Plastik,Installation,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Nothing and Everything: Seven Artists, 1947-1962, Hauser & Wirth, 2.2.2017 - 1.4.2017",Nothing and Everything,"Seven Artists, 1947-1962",,,,Gruppenausstellung,Sonderausstellung,,,,,Grafik,4021845-4,Plastik,4046277-8,Malerei,4037220-0,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Dreishpoon, Douglas",1057223557,Kurator:in,,"Bourgeois, Louise",118943375,Künstler:in,"Cage, John",Künstler:in,"Feldman, Morton",Künstler:in,"Guston, Philip",Künstler:in,"Kline, Franz",Künstler:in,"Mitchell, Joan",Künstler:in,"Smith, David",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,2,2,2017,,1,4,2017,Private View,2,2,2017,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,Plastik,Malerei,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Berlinde de Bruyckere - No Life Lost, Hauser & Wirth, 28.1.2016 - 2.4.2016",Berlinde de Bruyckere - No Life Lost,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Bruyckere, Berlinde de",119325047,Bildhauer:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,28,1,2016,,2,4,2016,Private View,28,1,2016,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Larry Bell - From the '60s, Hauser & Wirth, 3.2.2016 - 9.4.2016",Larry Bell - From the '60s,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Bell, Larry",120666367,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,2,2016,,9,4,2016,Private View,3,2,2016,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Fausto Melotti, Hauser & Wirth, 20.4.2016 - 18.6.2016",Fausto Melotti,,6072450-X,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,Installation,1228235120,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Fogle, Douglas",1011901633,Kurator:in,,"Melotti, Fausto",119212137,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,20,4,2016,,18,6,2016,Private View,20,4,2016,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,Installation,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Rita Ackermann - Negative Muscle, Hauser & Wirth, 5.3.2013 - 20.4.2013",Rita Ackermann - Negative Muscle,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Ackermann, Rita",128576022,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,3,2013,,20,4,2013,Private View,5,3,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"A Visual Essay on Gutai at 32 East 69th Street, Hauser & Wirth, 12.9.2012 - 27.10.2012",A Visual Essay on Gutai at 32 East 69th Street,,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,4037220-0,Grafik,4021845-4,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Nishizawa, Midori",188420703,Kurator:in,,"Renaud-Clément, Olivier",1136441522,Organisator:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,12,9,2012,,27,10,2012,Private View,12,9,2012,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,Grafik,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Fausto Melotti - The Deserved City, Hauser & Wirth, 13.9.2018 - 27.10.2018",Fausto Melotti - The Deserved City,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,Installation,1228235120,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Gnemmi, Edoardo",,Kurator:in,,"Melotti, Fausto",119212137,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,9,2018,,27,10,2018,Private View,13,9,2018,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,Installation,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Lygia Pape, Hauser & Wirth, 6.9.2018 - 20.10.2018",Lygia Pape,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,Malerei,4037220-0,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,2147407-2,,,,,,,,,,,,"Pape, Lygia",130504165,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,9,2018,,20,10,2018,Private View,6,9,2018,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,Malerei,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Bharti Kher - The Hot Winds That Blow from the West, Hauser & Wirth, 6.3.2012 - 14.4.2012",Bharti Kher - The Hot Winds That Blow from the West,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,,,,,,,,,,,,,"Kher, Bharti",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,3,2012,,14,4,2012,Vernissage,6,3,2012,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Zhang Enli, Hauser & Wirth, 15.9.2011 - 29.10.2011",Zhang Enli,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,,,,,,,,,,,,,"Enli, Zhang",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,15,9,2011,,29,10,2011,Vernissage,15,9,2011,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Monika Sosnowska - Tower, Hauser & Wirth, 5.9.2014 - 24.10.2014",Monika Sosnowska - Tower,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,,,,,,,,,,,,,"Sosnowska, Monika",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,9,2014,,24,10,2014,Private View,5,9,2014,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Fabio Mauri - I was not new, Hauser & Wirth, 5.3.2015 - 2.5.2015",Fabio Mauri - I was not new,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,Grafik,,Objektkunst,,Bildhauerei,,Installation,,New York,4042011-5,,,,,,,Hauser & Wirth,,,,,,,,,,,,,"Mauri, Fabio",,Künstler:in,,"Renaud-Clément, Olivier",,Organisator:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,3,2015,,2,5,2015,Private View,5,3,2015,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Roni Horn - ""Everything Was Sleeping As If The Universe Were a Mistake"", Hauser & Wirth, 11.11.2013 - 11.1.2014","Roni Horn - ""Everything Was Sleeping As If The Universe Were a Mistake""",,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,,,,,,,,,,,,,"Horn, Roni",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,11,2013,,11,1,2014,Private View,11,11,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Subodh Gupta - A glass of water, Hauser & Wirth, 5.5.2011 - 18.6.2011",Subodh Gupta - A glass of water,,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,,,,,,,,,,,,,"Gupta, Subodh",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,5,2011,,18,6,2011,Vernissage,5,5,2011,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"David Zink Yi - Pneuma, Hauser & Wirth, 29.6.2011 - 30.7.2011",David Zink Yi - Pneuma,,,,,Einzelausstellung,Sonderausstellung,,,,,Medienkunst,,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,,,,,,,,,,,,,"Yi, David Zink",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,29,6,2011,,30,7,2011,Private View,29,6,2011,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Paul McCarthy - Life Cast, Hauser & Wirth, 10.5.2013 - 26.7.2013",Paul McCarthy - Life Cast,,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,Installation,,Performance,,Medienkunst,,,,New York,4042011-5,,,,,,,Hauser & Wirth,,,,,,,,,,,,,"McCarthy, Paul",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,5,2013,,26,7,2013,Private View,10,5,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Paul McCarthy - Sculptures, Hauser & Wirth, 10.5.2013 - 1.6.2013",Paul McCarthy - Sculptures,,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,,,,,,,,,,,,,"McCarthy, Paul",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,5,2013,,1,6,2013,Private View,10,5,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Paul McCarthy, Damon McCarthy - Rebel Dabble Babble, Hauser & Wirth, 20.6.2013 - 26.7.2013","Paul McCarthy, Damon McCarthy - Rebel Dabble Babble",,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,,,,,,,,,,,,,"McCarthy, Paul",,Künstler:in,,"McCarthy, Damon",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,20,6,2013,,26,7,2013,Private View,20,6,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Trade Routes, Hauser & Wirth, 3.5.2013 - 27.7.2013",Trade Routes,,,,,Gruppenausstellung,Sonderausstellung,,,,,Medienkunst,,Installation,,Bildhauerei,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,,,,,,,,,,,,,"Abidin, Adel",,Künstler:in,,"Al Qadiri, Fatima",,Künstler:in,"Al Gharaballi, Khalid",Künstler:in,"Boetti, Alighiero",Künstler:in,"FarmanFarmaian, Monir",Künstler:in,"Gupta, Subodh",Künstler:in,"Karamustafa, Gülsün",Künstler:in,"Kher, Bharti",Künstler:in,"Koraichi, Rachid",Künstler:in,"Xe, Lee",Künstler:in,"Malluh, Maha",Künstler:in,"Pousttchi, Bettina",Künstler:in,"Sharif, Hassan",Künstler:in,"Shawky, Wael",Künstler:in,"Yi, David Zink",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,5,2013,,27,7,2013,Private View,2,5,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Rite of Passage: The Early Years of Vienna Actionism 1960-1966, Hauser & Wirth, 9.9.2014 - 25.10.2014",Rite of Passage,The Early Years of Vienna Actionism 1960-1966,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,Malerei,,Grafik,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,,,,,,,,,,,,,"Klocker, Hubert",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,9,2014,,25,10,2014,Private View,9,9,2014,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Hauser & Wirth],"Roni Horn, Hauser & Wirth, 7.5.2010 - 19.6.2010",Roni Horn,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Hauser & Wirth,,,,,,,,,,,,,"Horn, Roni",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hauser & Wirth,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,5,2010,,19,6,2010,Vernissage,7,5,2010,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sotheby's],"Important Photographs, Sotheby's, 2.10.1998 - ..",Important Photographs,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Sotheby's,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sotheby's,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,2,10,1998,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sotheby's],"Select Photographs from The Life Gallery of Photography, Sotheby's, 1.10. - 4.10.",Select Photographs from The Life Gallery of Photography,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,Chicago,,,,,,Sotheby's,,,,,,,,,,,,,"Weston, Edward",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sotheby's,Veranstalter,eBay,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,1,10,,,4,10,,,,,,,18,10,,,22,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sotheby's],"Fantastic: Photographs on Sothebys.com presented by eBay, Sotheby's",Fantastic: Photographs on Sothebys.com presented by eBay,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Sotheby's,,,,,,,,,,,,,"Eisenstaedt, Alfred",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sotheby's,Veranstalter,eBay,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sotheby's],"collection of 80s and 90s art, Sotheby's, 2.5.1997 - ..",collection of 80s and 90s art,,,,,Gruppenausstellung,Sonderausstellung,,,,,Bildhauerei,,,,,,,,,,New York,4042011-5,,,,,,,Sotheby's,,,,,,,,,,,,,"Gober, Robert",,Künstler:in,,"Barney, Matthew",,Künstler:in,"Smith, Kiki",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sotheby's,Veranstalter,Boston Children's Heart Foundation,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,2,5,1997,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +https://www.icp.org/exhibitions/john-wood-quiet-protest,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"John Wood: Quiet Protest, International Center of Photography, 15.5.2009 - 6.9.2009",John Wood: Quiet Protest,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Wood, John",136718973,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,15,5,2009,,6,9,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"David Seidner: Paris Fashions - 1945, International Center of Photography, 15.5.2009 - 6.9.2009",David Seidner: Paris Fashions - 1945,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Seidner, David",118883739,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,15,5,2009,,6,9,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Avedon Fashion 1944-2000, International Center of Photography, 15.5.2009 - 5.9.2009",Avedon Fashion 1944-2000,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,"Richard Avedon Foundation, new York",,,Kooperationspartner,"Fraenkel Gallery, San Francisco",Kooperationspartner,"Pace/MacGill Gallery, New York",Kooperationspartner,,,,,,,,,,,,,,,,,15,5,2009,,5,9,2009,Vernissage,15,5,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Dress Codes - The Third ICP Triennial of Photography and Video, International Center of Photography, 2.10.20109 - 17.1.2010",Dress Codes - The Third ICP Triennial of Photography and Video,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,Medienkunst,4113418-7,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Barrada, Yto",12980634X,Künstler:in,,"Belin, Valérie",120413043,Künstler:in,"Brinkmann, Thorsten",Künstler:in,"Fei, Cao",Künstler:in,"Chernysheva, Olga",Künstler:in,"Djurberg, Nathalie",Künstler:in,"Douglas, Stan",Künstler:in,"Ezawa, Kota",Künstler:in,"Hassink, Jacqueline",Künstler:in,"Yang, Hu",Künstler:in,"Ishiuchi, Miyako",Künstler:in,Kimsooja,Künstler:in,"Kolbowski, Silvia",Künstler:in,"Kost, Jeremy",Künstler:in,"Kruger, Barbara",Künstler:in,"Learoyd, Richard",Künstler:in,"Linzy, Kalup",Künstler:in,"Marcuse, Tanya",Künstler:in,"Morgenstern, Anne",Künstler:in,"Mutu, Wangechi",Künstler:in,"Ndiritu, Grace",Künstler:in,"O'Malley, Alice",Künstler:in,"Rosetzky, David",Künstler:in,"Rosler, Martha",Künstler:in,"Rudelius, Julika",Künstler:in,"Sherman, Cindy",Künstler:in,"Simmons, Laurie",Künstler:in,"Simpson, Lorna",Künstler:in,"Thomas, Hank Willis",Künstler:in,"Thomas, Mickalene",Künstler:in,"de la Torre, Milagros",Künstler:in,"Tschäpe, Janaina",Künstler:in,"Yolacan, Pinar",Künstler:in,"Tao, Zhou",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,ICP Exhibitions Committee,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,2,10,20109,,17,1,2010,Vernissage,1,10,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,Medienkunst,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"The Photographs of Ramon Vishniac: Man, Nature and Science 1930-1985, International Center of Photography",The Photographs of Ramon Vishniac,"Man, Nature and Science 1930-1985",,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography Midtown ,1082681-6,,,,,,,,,,,,"Vishniac, Roman",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Member's Reception,28,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Cornell Capa - Photographer, International Center of Photography, 14.9.1994 - 27.11.1994",Cornell Capa - Photographer,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Capa, Cornell",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,9,1994,,27,11,1994,Vernissage,13,9,1994,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"PhotoDiary - Lynn Goldsmith, International Center of Photography, 5.5.1995 - 16.7.1995",PhotoDiary - Lynn Goldsmith,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Goldsmith, Lynn",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,5,1995,,16,7,1995,Vernissage,4,5,1995,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"From Alice to Ocean: Alone Across the Outback, International Center of Photography, 27.7.1993 - 2.10.1993",From Alice to Ocean,Alone Across the Outback,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Smolan, Rick",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,27,7,1993,,2,10,1993,Member's Reception,29,7,1993,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Hiroshima Ground Zero 1945, International Center of Photography, 20.5.2011 - 28.8.2011",Hiroshima Ground Zero 1945,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,20,5,2011,,28,8,2011,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Magnum - Contact Sheets, International Center of Photography, 20.1.2012 - 2.9.2012",Magnum - Contact Sheets,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Burri, René",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,Magnum Photos,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,20,1,2012,,2,9,2012,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Elliott Erwitt (Personal Best), International Center of Photography, 20.5.2011 - 28.8.2011",Elliott Erwitt (Personal Best),,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Erwitt, Elliott",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,20,5,2011,,28,8,2011,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Patrons Preview: Elliott Erwitt: Personal Best, Ruth Gruber, photojournalist, Hiroshima: Ground Zero 1945, International Center of Photography",Patrons Preview,"Elliott Erwitt: Personal Best, Ruth Gruber, photojournalist, Hiroshima: Ground Zero 1945",,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Erwitt, Elliott",,Künstler:in,,"Gruber, Ruth",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Patrons Preview,19,5,2011,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Ruth Gruber / Photojournalist, International Center of Photography, 20.5.2011 - 28.8.2011",Ruth Gruber / Photojournalist,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Gruber, Ruth",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,20,5,2011,,28,8,2011,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Christer Strömholm - Les Amies de Place Blanche, International Center of Photography, 18.5.2012 - 2.9.2012",Christer Strömholm - Les Amies de Place Blanche,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Strömholm, Christer",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,18,5,2012,,2,9,2012,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Perspectives 2012: Anna Shteynshleyger, Greg Girard, Chien-Chi Chang, International Center of Photography, 20.1.2012 - 2.9.2012",Perspectives 2012,"Anna Shteynshleyger, Greg Girard, Chien-Chi Chang",,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Shteynshleyger, Anna",,Künstler:in,,"Girard, Greg",,Künstler:in,"Chang, Chien-Chi",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,20,1,2012,,2,9,2012,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"The Loving Story - Photographs by Grey Villet, International Center of Photography, 20.1.2012 - 2.9.2012",The Loving Story - Photographs by Grey Villet,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,20,1,2012,,2,9,2012,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Patrons & Members Preview: Weegee: Murder Is My Business, Perspectives 2012, The Loving Story: Photographs by Grey Villet, Magnum Contact Sheets, International Center of Photography, 19.1.2012 - ..",Patrons & Members Preview,"Weegee: Murder Is My Business, Perspectives 2012, The Loving Story: Photographs by Grey Villet, Magnum Contact Sheets",,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Villet, Grey",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,19,1,2012,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Weegee Murder is My Business, International Center of Photography, 20.1.2012 - 2.9.2012",Weegee Murder is My Business,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,Weegee,,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,20,1,2012,,2,9,2012,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Divine Inspiration: From Benin to Bahia, Photographs by Phyllis Galembo, International Center of Photography, 5.2.1993 - 28.3.1993",Divine Inspiration,"From Benin to Bahia, Photographs by Phyllis Galembo",,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Galembo, Phyllis",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,2,1993,,28,3,1993,Member's Reception,4,2,1993,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Juan Downey - The Thinking Eye Series, International Center of Photography, 24.4. - 14.6.",Juan Downey - The Thinking Eye Series,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Downey, Juan",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,24,4,,,14,6,,Member's Reception,23,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Ruth Orkin - A Retrospective, International Center of Photography, 5.5.1995 - 16.7.1995",Ruth Orkin - A Retrospective,,,Lucky Strikes: Photographs by Toby Old,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Orkin, Ruth",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,5,1995,,16,7,1995,Vernissage,4,5,1995,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Dorothea Lange - American Photographs, International Center of Photography, 3.3.1995 - 30.4.1995",Dorothea Lange - American Photographs,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Lange, Dorothea",,Fotograf:in,,"Phillips, Sandra S.",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,San Francisco Museom of Modern Art,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,3,3,1995,,30,4,1995,Vernissage,2,3,1995,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"The East Side Story: Photographs by L.A. Gangs, Joseph Rodriguez, International Center of Photography, 3.3.1995 - 30.4.1995",The East Side Story,"Photographs by L.A. Gangs, Joseph Rodriguez",,,,Einzelausstellung,Sonderausstellung,,,The New Documentarians,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Rodriguez, Joseph",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,3,1995,,30,4,1995,Vernissage,2,3,1995,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Lars Tunbjörk - Country Beside Itself, International Center of Photography, 1.12.1995 - 11.2.1996",Lars Tunbjörk - Country Beside Itself,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Tunbjörk, Lars",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,"Hasselblad Center, Stockholm",,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,1,12,1995,,11,2,1996,Vernissage,30,11,1995,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Appalachian Portraits - Photographs by Shelby Lee Adams, International Center of Photography, 23.9.1994 - 27.11.1994",Appalachian Portraits - Photographs by Shelby Lee Adams,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Adams, Shelby Lee",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,23,9,1994,,27,11,1994,Vernissage,22,9,1994,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Arthur Rothstein - Documentary Classics, International Center of Photography, 23.9.1994 - 4.12.1994",Arthur Rothstein - Documentary Classics,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Rothstein, Arthur",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,23,9,1994,,4,12,1994,Vernissage,22,9,1994,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Workers - An Archeology of the Industrial Age: Photographs by Sebastiao Salgado, International Center of Photography, 17.2.1995 - 26.5.1995",Workers - An Archeology of the Industrial Age,Photographs by Sebastiao Salgado,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Salgaado, Sebastiao",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,Alfred Stieglitz Center of the Philadelphia Museum of Art,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,17,2,1995,,26,5,1995,Vernissage,17,2,1995,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Josef Sudek - The Pigment Prints 1947-1954, International Center of Photography, 5.4.1996 - 7.7.1996",Josef Sudek - The Pigment Prints 1947-1954,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Sudek, Josef",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,Czech Center New York,,,Kooperationspartner,"Image Management, Amsterdam",Kooperationspartner,,,,,,,,,,,,,,,,,,,5,4,1996,,7,7,1996,Vernissage,12,4,1996,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Horst - A Retrospective, International Center of Photography Midtown , 29.3.1996 - 2.6.1996",Horst - A Retrospective,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography Midtown ,1082681-6,,,,,,,,,,,,Horst,,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography Midtown ,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,29,3,1996,,2,6,1996,Vernissage,28,3,1996,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Robert Smithson - Photo Works, International Center of Photography, 17.12.1993 - 13.2.1994",Robert Smithson - Photo Works,,,Photographs by Marvin Koner,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Smithson, Robert",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,Los Angeles County Museum of Art,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,17,12,1993,,13,2,1994,Vernissage,16,12,1993,,17,12,1994,,27,2,1994,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Under Lock and Key, International Center of Photography, 17.12.1994 - 13.2.1994",Under Lock and Key,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,4045895-7,Medienkunst,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"B, Beth",,Künstler:in,,"Horrigan, William",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,17,12,1994,,13,2,1994,Vernissage,16,12,1994,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,Medienkunst,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Robert Smithson and His Photographic Legacy, International Center of Photography, 20.1.1994 - ..",Robert Smithson and His Photographic Legacy,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Smithson, Robert",,Künstler:in,,"Sobieszek, Robert A.",,Kurator:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,20,1,1994,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Fundamentals of Legerdemain: An Installation by Alexander Hahn, International Center of Photography, 8.10.1995 - 8.1.1996",Fundamentals of Legerdemain,An Installation by Alexander Hahn,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Hahn, Alexander",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,10,1995,,8,1,1996,Vernissage,10,10,1995,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Cycles - Photographs by Judy Dater, International Center of Photography, 29.1.1994 - 2.4.1994",Cycles - Photographs by Judy Dater,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Dater, Judy",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,29,1,1994,,2,4,1994,Vernissage,28,1,1994,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Feeling the Spirit: Searching The World for the People of Africa by Chester Higgins Jr., International Center of Photography, 8.10.1995 - 8.1.1996",Feeling the Spirit: Searching The World for the People of Africa by Chester Higgins Jr.,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Jr. Higgins, Chester",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,10,1995,,8,1,1996,Vernissage,10,10,1995,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"William Klein: In & Out of Fasion, International Center of Photography, 3.12.1994 - 26.2.1995",William Klein: In & Out of Fasion,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Klein, William",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,12,1994,,26,2,1995,Vernissage,2,12,1994,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Emerging Photographers: Award-Winning Work by New York City Students, International Center of Photography, 8.6.1995 - 16.7.1995",Emerging Photographers,Award-Winning Work by New York City Students,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,6,1995,,16,7,1995,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Landscapes of the Civil War: Newly Discovered Photographs from the Medford Historical Society, International Center of Photography, 12.7.1996 - 10.11.1996",Landscapes of the Civil War,Newly Discovered Photographs from the Medford Historical Society,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Barnard, George N.",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,12,7,1996,,10,11,1996,Vernissage,18,7,1996,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Written in Memory - Portraits of the Holocaust: Photographs by Jeffrey A. Wolin, International Center of Photography Midtown, 14.2.1997 - 20.4.1997",Written in Memory - Portraits of the Holocaust,Photographs by Jeffrey A. Wolin,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography Midtown ,1082681-6,,,,,,,,,,,,"Wolin, Jefrey A.",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography Midtown,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,2,1997,,20,4,1997,Vernissage,13,2,1997,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"War Story: An Installation of Photographs by Mikael Levin, International Center of Photography Midtown, 14.2.1997 - 20.4.1997",War Story,An Installation of Photographs by Mikael Levin,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography Midtown,1082681-6,,,,,,,,,,,,"Levin, Mikael",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography Midtown,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,2,1997,,20,4,1997,Vernissage,13,2,1997,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"War Story: Spot News and Street Photography by Andrew Savulich, International Center of Photography, 4.3.1994 - 8.5.1994",Urban Realities,Spot News and Street Photography by Andrew Savulich,,,,Einzelausstellung,Sonderausstellung,,,The New Documentaries,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Savulich, Andrew",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,4,3,1994,,8,5,1994,Vernissage,3,3,1994,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Intimate Visions: The Photographs of Dorothy Norman, International Center of Photography, 2.4.1993 - 27.6.1993",Intimate Visions,The Photographs of Dorothy Norman,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Norman, Dorothy",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,2,4,1993,,27,6,1993,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Malcolm X - A Photo History, International Center of Photography, 2.4.1993 - 27.6.1993",Malcolm X - A Photo History,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,2,4,1993,,27,6,1993,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"From Sea To Shining Sea - A Portrait of America: photographed by Hiroji Kubota, International Center of Photography, 15.11.1992 - 31.1.1993",From Sea To Shining Sea - A Portrait of America,photographed by Hiroji Kubota,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Kubota, Hiroji",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,15,11,1992,,31,1,1993,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"David Bailey- The Sixties, International Center of Photography, 3.2. - 8.4.",David Bailey- The Sixties,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,1082681-6,,,,,,,,,,,,"Bailey, David",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,2,,,8,4,,Vernissage,2,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Ferenc Berko - The Discovering Eye, International Center of Photography Midtown - Permanent Collection Gallery, 15.7.1994 - 18.9.1994",Ferenc Berko - The Discovering Eye,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography Midtown - Permanent Collection Gallery,,,,,,,,,,,,,"Berko, Ferenc",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography Midtown - Permanent Collection Gallery,Veranstalter,Kodakt AG Stuttgart,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,15,7,1994,,18,9,1994,Vernissage,14,7,1994,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - International Center of Photography],"Cornell Capa - Photographer, International Center of Photography",Cornell Capa - Photographer,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,International Center of Photography,,,,,,,,,,,,,"Capa, Cornell",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,International Center of Photography,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Preview,12,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Ted Croner - New York 1947-1952, Howard Greenberg Gallery, 2.3.1995 - 8.4.1995",Ted Croner - New York 1947-1952,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Croner, Ted",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,2,3,1995,,8,4,1995,Vernissage,1,3,1995,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Women of the The Clarence H. White School of Photography , Howard Greenberg Gallery, 22.11.1996 - 18.1.1997",Women of the The Clarence H. White School of Photography ,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Brigman, Anne",,Fotograf:in,,"Gilpin, Laura",,Fotograf:in,"Hervey, Antoinette",Fotograf:in,"Lange, Dorothea",Fotograf:in,"Richards, Wynn",Fotograf:in,"Simon, Stella",Fotograf:in,"Sipprell, Clara",Fotograf:in,"Ulmann, Doris",Fotograf:in,"Watkins, Margaret",Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,22,11,1996,,18,1,1997,Vernissage,21,11,1996,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Ralph Eugene Meatyard - Master Prints, Howard Greenberg Gallery, 13.3.1998 - 25.4.1998",Ralph Eugene Meatyard - Master Prints,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Meatyard, Ralph Eugene",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,3,1998,,25,4,1998,Vernissage,12,3,1998,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Leon Levinstein - Living in the Edge, Howard Greenberg Gallery, 29.10.2010 - 4.12.2010",Leon Levinstein - Living in the Edge,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Levinstein, Leon",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,29,10,2010,,4,12,2010,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Bruce Davidson - Inside/Outside: vintage photographs from the artist's personal archive, Howard Greenberg Gallery, 26.9.2003 - 1.11.2003",Bruce Davidson - Inside/Outside,vintage photographs from the artist's personal archive,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Davidson, Bruce",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,26,9,2003,,1,11,2003,Vernissage,24,9,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Halsman|Dali, Howard Greenberg Gallery, 6.2.2004 - 13.3.2004",Halsman|Dali,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Halsman, Philippe",,Fotograf:in,,"Dali, Salvador",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,2,2004,,13,3,2004,Vernissage,6,2,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Kenro Izu - Blue, Howard Greenberg Gallery, 16.9.2004 - 23.10.2004",Kenro Izu - Blue,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Izu, Kenro",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,16,9,2004,,23,10,2004,Vernissage,15,9,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Helmar Lerski - Metamorphosis, Howard Greenberg Gallery, 16.9.2004 - 23.10.2004",Helmar Lerski - Metamorphosis,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Lerski, Helmar",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,16,9,2004,,23,10,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Six From The Seventies - The last Years of Modern Photography, Howard Greenberg Gallery, 18.6.2004 - 31.7.2004",Six From The Seventies - The last Years of Modern Photography,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Bishop, Michael",,Fotograf:in,,"Gohlke, Frank",,Fotograf:in,"Larson, William",Fotograf:in,"Martone, Michael",Fotograf:in,"Meyerowitz, Joel",Fotograf:in,"Nettles, Bea",Fotograf:in,"Wester, Rick",Kurator:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,18,6,2004,,31,7,2004,Artist's Reception,17,6,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Confidence - Mark Osterman, Howard Greenberg Gallery, 6.2.2004 - 13.3.2004",Confidence - Mark Osterman,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Osterman, Mark",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,2,2004,,13,3,2004,Vernissage,5,2,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"In Celebration of Magnum in May, Howard Greenberg Gallery",In Celebration of Magnum in May,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Capa, Robert",,Fotograf:in,,"Cartier-Bresson, Henri",,Fotograf:in,"Davidson, Bruce",Fotograf:in,"Franck, Martine",Fotograf:in,"Riboud, Marc",Fotograf:in,"Seymour, David",Fotograf:in,"Steele-Perkins, Chris",Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,The Estate of Inge Morath,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"circa 1947 - The Founding of Magnum, Howard Greenberg Gallery, 30.4.2004 - 12.6.2004",circa 1947 - The Founding of Magnum,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Capa, Robert",,Fotograf:in,,"Cartier-Bresson, Henri",,Fotograf:in,"Seymour, David",Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,30,4,2004,,12,6,2004,Vernissage,29,4,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Subway - Bruce Davidson, Howard Greenberg Gallery, 30.4.2004 - 12.6.2004",Subway - Bruce Davidson,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Davidson, Bruce",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,30,4,2004,,12,6,2004,Vernissage,29,4,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Tato - Experimental Light, Howard Greenberg Gallery, 19.3.2004 - 24.4.2004",Tato - Experimental Light,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"?, Tato",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,19,3,2004,,24,4,2004,Vernissage,18,3,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Ukiyso-e Projections: Eikoh Hosoe's Photographic Theater, Howard Greenberg Gallery, 19.3.2004 - 24.4.2004",Ukiyso-e Projections,Eikoh Hosoe's Photographic Theater,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,Installation,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Hosoe's, Eikoh",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,19,3,2004,,24,4,2004,Vernissage,18,3,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,Installation,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Dan Weiner - American Photographs 1936-1959, Howard Greenberg Gallery, 1.5.1998 - 13.6.1998",Dan Weiner - American Photographs 1936-1959,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Weiner, Dan",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,1,5,1998,,13,6,1998,Vernissage,30,4,1998,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Snapshot Poetics - photographs by Allen Ginsberg, Howard Greenberg Gallery, 6.9.2002 - 12.10.2002",Snapshot Poetics - photographs by Allen Ginsberg,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Ginsberg, Allen",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,Allen Ginsberg photographic archive,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,6,9,2002,,12,10,2002,Vernissage,5,9,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Vivian Maier, Howard Greenberg Gallery, 15.12.2011 - 28.1.2012",Vivian Maier,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Maier, Vivian",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,15,12,2011,,28,1,2012,Vernissage,15,12,2011,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Ginsberg, Howard Greenberg Gallery, 27.1.2011 - 12.3.2011",Ginsberg,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Ginsberg, ?",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,27,1,2011,,12,3,2011,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"George Segal - Sequence: New York / New Jersey 1990-1993, Howard Greenberg Gallery, 22.10.1993 - 27.11.1993",George Segal - Sequence: New York / New Jersey 1990-1993,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Segal, George",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,22,10,1993,,27,11,1993,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"The Photofind Collection: An inaugural exhibition of fine vintage photography from 1900 to 1960, Howard Greenberg/Photofind, 23.9. - 25.10.",The Photofind Collection,An inaugural exhibition of fine vintage photography from 1900 to 1960,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg/Photofind,,,,,,,,,,,,,"Abbott, ?",,Fotograf:in,,"Brassai, ?",,Fotograf:in,"Collins, ?",Fotograf:in,"Cramer, ?",Fotograf:in,"Cunningham, ?",Fotograf:in,"Delano, ?",Fotograf:in,"Disraeli, ?",Fotograf:in,"Grossman, ?",Fotograf:in,"Kattelson, ?",Fotograf:in,"Kuniyoshi, ?",Fotograf:in,"Lapow, ?",Fotograf:in,"Lee, ?",Fotograf:in,"Leipzig, ?",Fotograf:in,"Levenstein, ?",Fotograf:in,"Libsohn, ?",Fotograf:in,"Munkacsi, ?",Fotograf:in,"Rittase, ?",Fotograf:in,"Robbins, ?",Fotograf:in,"Rosskam, ?",Fotograf:in,"Seeley, ?",Fotograf:in,"Shahn, ?",Fotograf:in,"Shields, ?",Fotograf:in,"Stock, ?",Fotograf:in,"Strand, ?",Fotograf:in,"Teske, ?","van der Zee, ?",Fotograf:in,"Watson-Schütze, ?",Fotograf:in,"Weiner, ?",Fotograf:in,"Weiss, ?",Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg/Photofind,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,23,9,,,25,10,,opening party,23,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"The Flower Show by Dennis Stock, Howard Greenberg/Photofind, 4.10.1986 - 16.11.1986",The Flower Show by Dennis Stock,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg/Photofind,,,,,,,,,,,,,"Stock, Dennis",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg/Photofind,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,4,10,1986,,16,11,1986,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"William Klein: New York 1954.55: Unseen and Unpublished Photographs, Howard Greenberg Gallery, 29.3.1996 - 11.5.1996",William Klein: New York 1954.55,Unseen and Unpublished Photographs,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Klein, William",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,Gallery 292,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,29,3,1996,,11,5,1996,Vernissage,27,3,1996,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Kenro Izu - Still Life, Howard Greenberg Gallery, 11.12.1998 - 23.1.1999",Kenro Izu - Still Life,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Izu, Kenro",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,12,1998,,23,1,1999,Artist Reception,10,12,1999,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Arnold Newman - Vintage Photographs & Color, Howard Greenberg Gallery, 7.5.1999 - 19.6.1999",Arnold Newman - Vintage Photographs & Color,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Newman, Arnold",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,5,1999,,19,6,1999,Artist Reception,13,5,1999,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Imogen Cunningham, Howard Greenberg Gallery, 15.9.1995 - 4.11.1995",Imogen Cunningham,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Cunningham, Imogen",,Fotograf:in,,"Lorenz, Richard",,Kurator:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,15,9,1995,,4,11,1995,Vernissage,14,9,1995,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Kenro Izu - Light Over Ancient Angkor, Howard Greenberg Gallery, 24.1.1997 - 22.2.1997",Kenro Izu - Light Over Ancient Angkor,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Izu, Kenro",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,Tenri Gallery,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,24,1,1997,,22,2,1997,Vernissage,23,1,1997,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Richard Gere - Pilgrim: Photographs in conjunction with the publication, Pilgrim (Bulfinch Press, 1997), Howard Greenberg Gallery, 7.11.1997 - 6.12.1997",Richard Gere - Pilgrim,"Photographs in conjunction with the publication, Pilgrim (Bulfinch Press, 1997)",,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Gere, Richard",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,11,1997,,6,12,1997,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Frantisek Drtikol, Howard Greenberg Gallery, 7.11.1997 - 6.12.1997",Frantisek Drtikol,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Drtikol, Frantisek",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,11,1997,,6,12,1997,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"1930's New York: Vintage Photography by Berenice Abbott, Sol Prom, Joseph Kaplan and Liborio Justo, Howard Greenberg Gallery, 12.12.1998 - 17.1.1998",1930's New York,"Vintage Photography by Berenice Abbott, Sol Prom, Joseph Kaplan and Liborio Justo",,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Abbott, Berenice",,Fotograf:in,,"Prom, Sol",,Fotograf:in,"Kaplan, Joseph",Fotograf:in,"Justo, Liborio",Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,12,12,1998,,17,1,1998,Vernissage,11,12,1998,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Berenice Abbott - Changing New York: Bonnie Yochelson & The Museum of the City of New York, Howard Greenberg Gallery, 14.3.1998 - 21.6.1998",Berenice Abbott - Changing New York,Bonnie Yochelson & The Museum of the City of New York,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Abbott, Berenice",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,The Museum of the City of New York,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,14,3,1998,,21,6,1998,Vernissage,11,12,1997,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Robert Adams - A Remaining Harmony, Howard Greenberg Gallery, 16.2.1996 - 23.3.1996",Robert Adams - A Remaining Harmony,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Adams, Robert",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,16,2,1996,,23,3,1996,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Ed van der Elsken - Street Life, Howard Greenberg Gallery, 15.9.1993 - 16.10.1993",Ed van der Elsken - Street Life,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"van der Elsken, Ed",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,15,9,1993,,16,10,1993,Vernissage,14,9,1993,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Points of View - New York in the 1930s, Howard Greenberg Gallery, 3.12.1994 - 15.1.1994",Points of View - New York in the 1930s,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Abbott, Berenice",,Fotograf:in,,"Alland, Alexander",,Fotograf:in,"Eagle, Arnold",Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,12,1994,,15,1,1994,Vernissage,4,12,1994,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Take the A Train, Howard Greenberg Gallery, 19.6.1998 - 14.8.1998",Take the A Train,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Abbott, Berenice",,Fotograf:in,,"Bing, Ilse",,Fotograf:in,"Davidson, Bruce",Fotograf:in,"diCorcia, Phillip-Lorca",Fotograf:in,"Eagle, Arnold",Fotograf:in,"Eisenstaedt, Alfred",Fotograf:in,"Ellman, Elaine",Fotograf:in,"Evans, Walker",Fotograf:in,"Faurer, Louis",Fotograf:in,"Feininger, Andreas",Fotograf:in,"Ferrato, Donna",Fotograf:in,"Frank, Robert",Fotograf:in,"Freed, Leonard",Fotograf:in,"Gibson, Ralph",Fotograf:in,"Grunzweig, Bedrich",Fotograf:in,"Halsman, Philippe",Fotograf:in,"Himmel, Paul",Fotograf:in,"Kertész, André",Fotograf:in,"Klein, William",Fotograf:in,"Kubrick, Stanley",Fotograf:in,"Lapow, Harry",Fotograf:in,"Lavine, Arthur",Fotograf:in,"Leipzig, Arthur",Fotograf:in,"Leiter, Saul",Fotograf:in,"Lepkoff, Rebecca",Fotograf:in,"Lyon, Danny",Fotograf:in,"Meyerowitz, Joel",Fotograf:in,"Paulin, Frank",Fotograf:in,"Peress, Gilles",Fotograf:in,"Riis, Jacob",Fotograf:in,"Roma, Thomas",Fotograf:in,"Roth, Harold",Fotograf:in,"Silver, Larry",Fotograf:in,"Stieglitz, Alfred",Fotograf:in,"Strand, Paul",Fotograf:in,"Struss, Karl",Fotograf:in,"Weegee, ?",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,19,6,1998,,14,8,1998,Vernissage,18,6,1998,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Aaron Siskind - Photographs, Howard Greenberg Gallery, 7.5.1999 - 19.6.1999",Aaron Siskind - Photographs,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,Conference Room,,,,,,,,,,,,"Siskind, Aaron",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,5,1999,,19,6,1999,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Marc Riboud: Photographs, Howard Greenberg Gallery, 2.7.1997 - 15.8.1997",Marc Riboud: Photographs,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Riboud, Marc",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,2,7,1997,,15,8,1997,Artist's Reception,1,7,1997,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Paul Himmel & the Brodovitch Circle, Howard Greenberg Gallery, 17.5.1996 - 22.6.1996",Paul Himmel & the Brodovitch Circle,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Harrison, Martin",,Kurator:in,,"Himmel, Paul",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,17,5,1996,,22,6,1996,Vernissage,16,5,1996,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Frederic Brenner - Romanvs Judaeus: Une Memoire de Rome, 1992, Howard Greenberg Gallery, 4.3.1993 - 10.4.1993",Frederic Brenner - Romanvs Judaeus,"Une Memoire de Rome, 1992",,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Brenner, Frederic",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,4,3,1993,,10,4,1993,Vernissage,6,3,1993,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Arnold Newman - First Showing, Howard Greenberg Gallery, 24.4.1992 - 30.5.1992",Arnold Newman - First Showing,,,The Classic Newman: Vintage Photographs,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,Print Room Gallery,,,,,,,,,,,,"Newman, Arnold",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,24,4,1992,,30,5,1992,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Edward Burtynsky, Howard Greenberg Gallery, 27.10.2011 - 10.12.2011",Edward Burtynsky,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Burtynsky, Edward",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,27,10,2011,,10,12,2011,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Edward Burtynsky - Dryland Farming, Bryce Wolkowitz Gallery, 26.10.2011 - 10.12.2011",Edward Burtynsky - Dryland Farming,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Bryce Wolkowitz Gallery,,,,,,,,,,,,,"Burtynsky, Edward",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Bryce Wolkowitz Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,26,10,2011,,10,12,2011,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Iwao Yamawaki - collages and photographs, Howard Greenberg Gallery, 3.10.1996 - 16.11.1996",Iwao Yamawaki - collages and photographs,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Yamawaki, Iwao",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,10,1996,,16,11,1996,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"the fights: Classic Boxing Photographs by Charles Hoff in association with Constance Sullivan, Gallery 292, 3.10.1996 - 16.11.1996",the fights,Classic Boxing Photographs by Charles Hoff in association with Constance Sullivan,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Gallery 292,,,,,,,,,,,,,"Hoff, Charles",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gallery 292,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,10,1996,,16,11,1996,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Made for America (part 2), Howard Greenberg Gallery, 19.12.2003 - 31.1.2004",Made for America (part 2),,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Elisofon, Eliot",,Fotograf:in,,"Mydans, Carl",,Fotograf:in,"Lange, Dorothea",Fotograf:in,"Stackpole, Peter",Fotograf:in,"Crane, Ralph",Fotograf:in,"Parks, Gordon",Fotograf:in,"Bourke-White, Margaret",Fotograf:in,"Eisenstaedt, Alfred",Fotograf:in,"Smith, W. Eugene",Fotograf:in,"Capa, Robert",Fotograf:in,"Morse, Ralph",Fotograf:in,"Leen, Nina",Fotograf:in,"Mili, Gjon",Fotograf:in,"Salomon, Erich",Fotograf:in,"Evans, Walker",Fotograf:in,"Feininger, Andreas",Fotograf:in,"Bristol, Horace",Fotograf:in,"Sanders, Walter",Fotograf:in,"Munkacsi, Martin",Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,19,12,2003,,31,1,2004,Vernissage,18,12,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Eye Mind Spirit - the Enduring Legacy of Minor White, Howard Greenberg Gallery, 12.9.2008 - 18.10.2008",Eye Mind Spirit - the Enduring Legacy of Minor White,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"White, Minor",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,12,9,2008,,18,10,2008,Vernissage,11,9,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Frédéric Brenner - Jews America: a representation, Howard Greenberg Gallery, 17.9.1996 - 28.9.1996",Frédéric Brenner - Jews America,a representation,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Brenner, Frederic",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,17,9,1996,,28,9,1996,Vernissage,19,9,1996,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Art Sinsabaugh - An American Perspective, Howard Greenberg Gallery, 7.11.2003 - 13.12.2003",Art Sinsabaugh - An American Perspective,,,,,Einzelausstellung,Sonderausstellung,,,,,Design,,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Sinsabaugh, ?",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,11,2003,,13,12,2003,Vernissage,5,11,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Design,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Henry Wolf 1925-2005, Howard Greenberg Gallery, 16.9.2005 - 22.10.2005",Henry Wolf 1925-2005,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Wolf, Henry",,Künstler:in,,"Aletti, Vince",,Kurator:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,16,9,2005,,22,10,2005,Vernissage,15,9,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Ruth Orkin - Jinx Allen in Florence, Howard Greenberg Gallery, 16.9.2005 - 22.10.2005",Ruth Orkin - Jinx Allen in Florence,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Orkin, Ruth",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,16,9,2005,,22,10,2005,Vernissage,15,9,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Building the IRT 1900-1907 - New York, Howard Greenberg Gallery, 6.5.2005 - 18.6.2005",Building the IRT 1900-1907 - New York,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,5,2005,,18,6,2005,Vernissage,5,5,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Bill Burke - 30 years, Howard Greenberg Gallery, 6.5.2005 - 18.6.2005",Bill Burke - 30 years,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Burke, Bill",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,5,2005,,18,6,2005,Vernissage,5,5,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Walker Evans and his Early Circle, Howard Greenberg Gallery, 29.10.2004 - 4.12.2004",Walker Evans and his Early Circle,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Evans, Walker",,Fotograf:in,,"Abbott, Berenice",,Fotograf:in,"Levitt, Helen",Fotograf:in,"Sekaer, Peter",Fotograf:in,"Shahn, Ben",Fotograf:in,"Steiner, Ralph",Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,29,10,2004,,4,12,2004,Vernissage,28,10,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Dana Buckley: Fifty, Howard Greenberg Gallery, 28.1.2005 - 5.3.2005",Dana Buckley: Fifty,,,,,Einzelausstellung,Sonderausstellung,,,,,Schrift,,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Buckley, Dana",,Künstler:in,,"Hill, John T.",,Kurator:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Book Signing,13,11,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Schrift,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"André Kertész - Perception: A Selection of Exceptional Vintage Photographs, Howard Greenberg Gallery, 28.1.2005 - 5.3.2005",André Kertész - Perception,A Selection of Exceptional Vintage Photographs,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Kertész, André",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,28,1,2005,,5,3,2005,Vernissage,27,1,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Leon Levinstein - Obsession, Howard Greenberg Gallery, 28.1.2005 - 5.3.2005",Leon Levinstein - Obsession,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Levinstein, Leon",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,28,1,2005,,5,3,2005,Vernissage,27,1,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Dave Heath - Korea, Howard Greenberg Gallery, 28.1.2005 - 5.3.2005",Dave Heath - Korea,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Heath, Dave",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,28,1,2005,,5,3,2005,Vernissage,27,1,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Circus - Sarah Moon, Howard Greenberg Gallery, 10.12.2004 - 22.1.2005",Circus - Sarah Moon,,,,,Einzelausstellung,Sonderausstellung,,,,,Medienkunst,,Fotografie,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Moon, Sarah",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,12,2004,,22,1,2005,Vernissage,9,12,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Medienkunst,Fotografie,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Art Photography in Japan 1920-1940, Howard Greenberg Gallery, 21.3.2003 - 3.5.2003",Art Photography in Japan 1920-1940,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Yoshiro, Hirogane",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,"Charles Schwartz, LTD.",Kooperationspartner,,,,,,,,,,,,,,,,,,,,,,,21,3,2003,,3,5,2003,Vernissage,20,3,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Gordon Parks - Moments Without Proper Names, Howard Greenberg Gallery, 27.1.2006 - 11.3.2006",Gordon Parks - Moments Without Proper Names,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Parks, Gordon",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,27,1,2006,,11,3,2006,Vernissage,26,1,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"George Platt Lynes - Young Modernist C. 1928, Howard Greenberg Gallery, 28.10.2005 - 3.12.2005",George Platt Lynes - Young Modernist C. 1928,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Lynes, George Platt",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,28,10,2005,,3,12,2005,Vernissage,27,10,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Arnold Newman - Sessions, Howard Greenberg Gallery, 9.5.2003 - 14.6.2003",Arnold Newman - Sessions,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Newman, Arnold",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,5,2003,,14,6,2003,Vernissage,8,5,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Paul Strand - Northern Africa 1959-1963, Howard Greenberg Gallery, 26.11.2008 - 10.1.2009",Paul Strand - Northern Africa 1959-1963,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Strand, Paul",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,26,11,2008,,10,1,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Jessica Lange - Photographs, Howard Greenberg Gallery, 26.11.2008 - 10.1.2009",Jessica Lange - Photographs,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Lange, Jessica",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,26,11,2008,,10,1,2009,Vernissage,10,12,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Paul Strand, Howard Greenberg Gallery, 31.1.2003 - 15.3.2003",Paul Strand,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Strand, Paul",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,31,1,2003,,15,3,2003,Vernissage,30,1,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Howard Greenberg Gallery],"Charles Marville - Streetlamps of Paris, Howard Greenberg Gallery, 28.10.2005 - 3.12.2005",Charles Marville - Streetlamps of Paris,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,,,,,,,,,,,,,"Marville, Charles",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,28,10,2005,,3,12,2005,Vernissage,27,10,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Contemporary Art, Phillips de Pury & Company, 4.5. - 11.5.",Contemporary Art,,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"Dumas, Marlene",,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,4,5,,,11,5,,Auktion,11,5,,,,,,,,,,Auktion,12,5,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Design, Phillips de Pury & Company, 2.6. - 7.6.",Design,,,,,Gruppenausstellung,Sonderausstellung,,,,,Design,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"Newson, Marc",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,2,6,,,7,6,,Vernissage,5,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Design,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Contemporary Art & 14 Duchamp Readymades, Phillips de Pury & Company",Contemporary Art & 14 Duchamp Readymades,,,,,Gruppenausstellung,Sonderausstellung,,,,,Design,,Objektkunst,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"Noble, Tim",,Künstler:in,,"Webster, Sue",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Preview,9,5,,,,,,,,,,Auktion,13,5,,,,,,,,,,Auktion,14,5,,,,,,,,,,,,,,Flyer,Design,Objektkunst,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Contemporary Art and 20-21st Century Design Art and Photographs, Phillips de Pury & Company",Contemporary Art and 20-21st Century Design Art and Photographs,,,,,Gruppenausstellung,Sonderausstellung,,,,,Objektkunst,,Design,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"Hammons, David",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Preview,22,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Objektkunst,Design,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Photographs - An Invitation to Cosign for Spring 2006, Phillips de Pury & Company",Photographs - An Invitation to Cosign for Spring 2006,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"Friedlander, Lee",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Enzo Cucchi - Salute, Phillips de Pury & Company, 21.9. - 21.10.",Enzo Cucchi - Salute,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"Cucchi, Enzo",,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,21,9,,,21,10,,Vernissage,20,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Photographs, Phillips de Pury & Company, 19.4. - 205.4.",Photographs,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"Modotti, Tina",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,19,4,,,205,4,,Vernissage,20,4,,,,,,,,,,Auktion,26,4,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Contemporary Art, Phillips de Pury & Company, 2.5.2005 - 12.5.2005",Contemporary Art,,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,,Grafik,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"Martin, Agnes",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,2,5,2005,,12,5,2005,Vernissage,7,5,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,Grafik,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Saturday @ Phillips, Phillips de Pury & Company, 3.4. - 8.4.",Saturday @ Phillips,,,,,Gruppenausstellung,Sonderausstellung,,,,,Installation,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,4,,,8,4,,Auktion,8,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"George Clinton & Parliament/Funkadelic, Phillips de Pury & Company",George Clinton & Parliament/Funkadelic,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"Gurksy, Andreas",,Künstler:in,,"Clinton, George",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,handschriftlich,,,,,,,,,,Preview,10,5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Contemporary Art: Highlights Exhibition, Phillips de Pury & Company, 10.5.2005 - 24.5.2005",Contemporary Art,Highlights Exhibition,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,,Fotografie,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"Prince, Richard",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,5,2005,,24,5,2005,Vernissage,11,3,2005,,,,,,,,,Auktion,12,5,2005,,,,,,,,,Auktion,13,5,2005,,,,,,,,,,,,,Flyer,Malerei,Fotografie,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Saturday @ Phillips, Phillips de Pury & Company, 13.6. - 16.6.",Saturday @ Phillips,,,,,Gruppenausstellung,Sonderausstellung,,,,,Installation,,Design,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,6,,,16,6,,Auktion,17,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,Design,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Contemporary Art, Phillips de Pury & Company",Contemporary Art,,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,,Installation,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Auktion,16,11,2006,,,,,,,,,Auktion,17,11,2006,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,Installation,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Under the Influence II, Phillips de Pury & Company, 6.9. - 12.9.",Under the Influence II,,,Saturday @ Phillips,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"Uklanski, Piotr",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,9,,,12,9,,Auktion,12,9,,,6,9,,,16,9,,Auktion,16,9,,,,,,,,,,Vernissage,6,9,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Photographs, Phillips de Pury & Company",Photographs,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"Minuz, Vik",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Vernissage,25,4,,,,,,,,,,Auktion,27,4,,,,,,,,,,Auktion,28,4,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Selected Works by Mario Testino, Phillips de Pury & Company, 28.1.2006 - 17.2.2006",Selected Works by Mario Testino,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"Testino, Mario",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,28,1,2006,,17,2,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"20-21st Century Design Art, Phillips de Pury & Company, 3.12. - 8.12.",20-21st Century Design Art,,,,,Gruppenausstellung,Sonderausstellung,,,,,Design,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,Collection of Alexander von Vegesack,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,3,12,,,8,12,,Auktion,8,12,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Design,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"An Invitation to Consign for Fall 2006 - Photographs, Phillips de Pury & Company",An Invitation to Consign for Fall 2006 - Photographs,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"Clark, Larry",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Auktion,18,10,2006,,,,,,,,,Auktion,19,10,2006,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Photographs - Now Accepting Consignments for spring 2005, Phillips de Pury & Company",Photographs - Now Accepting Consignments for spring 2005,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"Dicorcia, Philip-Lorca",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Africa - Contemporary Art, Photographs, Editions, Phillips de Pury & Company, 6.5.2010 - 15.5.2010","Africa - Contemporary Art, Photographs, Editions",,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,,Fotografue,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"Samba, Chéri",,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,5,2010,,15,5,2010,Auktion,15,5,2010,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,Fotografue,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"The Estate of Mrs. Harry N. Abrams, Phillips de Pury & Company, 27.3.2010 - 7.4.2010",The Estate of Mrs. Harry N. Abrams,,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,27,3,2010,,7,4,2010,Vernissage,31,3,2010,,,,,,,,,Auktion,7,4,2010,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Under the Influence, Phillips de Pury & Company, 20.2. - 26.2.",Under the Influence,,,,,Gruppenausstellung,Sonderausstellung,,,,,Bildhauerei,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"Fischer, Urs",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,20,2,,,26,2,,Auktion,27,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Bildhauerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Under the Influence: New Art from India and Pakistan, Phillips de Pury & Company, 28.1.2009 - 14.2.2009",The Audience & the Eavesdropper,New Art from India and Pakistan,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"Abbas, Hamra",,Künstler:in,,"Chhachhi, Sheba",,Künstler:in,"Dube, Anita",Künstler:in,"Gupta, Probir",Künstler:in,"Ponmany, Justin",Künstler:in,Raqs Media Collective,Künstler:in,"Rana, Rashid",Künstler:in,"Singh, Samarendra Raj",Künstler:in,Thukral & Tagra,Künstler:in,"Upadhyay, Hema",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,28,1,2009,,14,2,2009,Vernissage,27,1,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"The Ship of Fools - Julian Rosefeldt, Phillips de Pury & Company, 10.1.2008 - 31.1.2008",The Ship of Fools - Julian Rosefeldt,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,1,2008,,31,1,2008,Vernissage,9,1,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Under the Influence, Phillips de Pury & Company",Under the Influence,,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"McGinness, Ryan",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Auktion,8,3,2012,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Photographs, Phillips de Pury & Company, 1.4.2011 - 8.4.2011",Photographs,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"Sherman, Cindy",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,1,4,2011,,8,4,2011,Vernissage,2,4,2011,,,,,,,,,Auktion,9,4,2011,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Contemporary Art, Phillips de Pury & Company, 30.10.2004 - 10.11.2004",Contemporary Art,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"Cattelan, Maurizio",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,30,10,2004,,10,11,2004,Vernissage,6,11,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Contemporary Art, Phillips de Pury & Company",Contemporary Art,,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"Richter, Gerhard",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Preview,7,11,,,,,,,,,,Auktion,11,11,,,,,,,,,,Auktion,12,11,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Contemporary Art, Phillips de Pury & Company, 11.3.2004 - 11.3.2004",Contemporary Art,,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"Cattelan, Maurizio",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,3,2004,,11,3,2004,Private Viewing,12,3,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Magnificent Jewels and Photographs, Phillips de Pury & Company",Magnificent Jewels and Photographs,,,,,Gruppenausstellung,Sonderausstellung,,,,,Design,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Preview,11,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Design,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Photographs, Phillips de Pury & Company, 22.4.2004 - 24.4.2004",Photographs,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,22,4,2004,,24,4,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Jewelry, Phillips de Pury & Company, 18.5.2004 - 24.6.2004",Jewelry,,,,,Gruppenausstellung,Sonderausstellung,,,,,Design,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,18,5,2004,,24,6,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Design,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Contemporary Art, Phillips de Pury & Company, 13.5.2004 - 14.5.2004",Contemporary Art,,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,5,2004,,14,5,2004,,10,6,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"20-21st Century Design Art, Phillips de Pury & Company",20-21st Century Design Art,,,,,Gruppenausstellung,Sonderausstellung,,,,,Design,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,10,6,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Design,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Artists for Chinati Foundation, Phillips de Pury & Company, 4.3.2006 - 13.3.2006",Artists for Chinati Foundation,,,,,Gruppenausstellung,Sonderausstellung,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,4,3,2006,,13,3,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Contemporary Art Auction, Phillips de Pury & Company, 4.3.2006 - 13.3.2006",Contemporary Art Auction,,,,,Gruppenausstellung,Sonderausstellung,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,4,3,2006,,13,3,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Saturday @ Phillips Auction, Phillips de Pury & Company, 3.4.2006 - 8.4.2006",Saturday @ Phillips Auction,,,,,Gruppenausstellung,Sonderausstellung,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,4,2006,,8,4,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Photographs Auction, Phillips de Pury & Company, 19.4.2006 - 25.4.2006",Photographs Auction,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,19,4,2006,,25,4,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Contemporary Art Part 1, Phillips de Pury & Company, 2.5.2006 - 11.5.2006",Contemporary Art Part 1,,,,,Gruppenausstellung,Sonderausstellung,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,2,5,2006,,11,5,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Contemporary Art Part II, Phillips de Pury & Company, 2.5.2006 - 11.5.2006",Contemporary Art Part II,,,,,Gruppenausstellung,Sonderausstellung,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,2,5,2006,,11,5,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Magnificent Jewels, Phillips de Pury & Company, 12.5.2006 - 16.5.2006",Magnificent Jewels,,,,,Gruppenausstellung,Sonderausstellung,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,12,5,2006,,16,5,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"20-21st Century Design Art, Phillips de Pury & Company, 3.6.2006 - 7.6.2006",20-21st Century Design Art,,,,,Gruppenausstellung,Sonderausstellung,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,6,2006,,7,6,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Saturday @ Phillips Auction, Phillips de Pury & Company, 13.6.2006 - 17.6.2006",Saturday @ Phillips Auction,,,,,Gruppenausstellung,Sonderausstellung,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,6,2006,,17,6,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Contemporary Art, Phillips de Pury & Company",Contemporary Art,,,,,Gruppenausstellung,Sonderausstellung,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"Cattelan, Maurizio",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Auktion,13,11,,,,,,,,,,Auktion,14,11,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"20-19th Century Design Art, Phillips de Pury & Company, 30.10.2002 - 5.11.2002",20-19th Century Design Art,,,,,Gruppenausstellung,Sonderausstellung,,,,,Design,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"Garner, Philippe",,Künstler:in,,"Payne, Alexander",,Künstler:in,"Zemaitis, James",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,30,10,2002,,5,11,2002,Auktion,11,12,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Design,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Phillips de Pury & Luxembourg],"Contemporary Art Fall 2002, Phillips de Pury & Company, 2.11.2002 - 10.11.2002",Contemporary Art Fall 2002,,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"Basquiat, Jean-Michel",,Künstler:in,,"Warhol, Andy",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,2,11,2002,,10,11,2002,Auktion,11,11,2002,,,,,,,,,Auktion,12,11,2002,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Christie's],,Donald Judd - Selected Works From the Judd Foundation,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Christie's,,,,,,,,,,,,,"Judd, Donald",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Christie's,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,4,2006,,9,5,2006,Auktion,9,5,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Christie's],"Photographs, Christie's",Photographs,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Christie's,,,,,,,,,,,,,"Leibovitz, Annie",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Christie's,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Auktion,1,11,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Christie's],"Post-War and Contemporary Art: An Exhibition of Highlights from an Important American Collection being sold by the JCF, Christie's",Post-War and Contemporary Art,An Exhibition of Highlights from an Important American Collection being sold by the JCF,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,,Bildhauerei,,,,,,,,New York,4042011-5,London,,Paris,,,,Christie's,,,,,,,,,,,,,"de Kooning, Willem",,Künstler:in,,"Gorky, Arshile",,Künstler:in,"Kline, Franz",Künstler:in,"Motherwell, Robert",Künstler:in,"Newman, Barnett",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Christie's,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Auktion,11,5,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,Bildhauerei,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Christie's],"Photographs, Christie's",Photographs,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,Los Angeles,,,,,,Christie's,,,,,,,,,,,,,"Muniz, Vik",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Christie's,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Auktion,4,10,2001,,,,,,,,,Auktion,5,10,2001,,,,,,,,,Auktion,13,11,2001,,,,,,,,,Auktion,16,1,2002,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Christie's],"Photographs: Inncluding Property from the Jackie Napolean Wilson Collection, Christie's, 28.9.2001 - 3.10.2001",Photographs,Inncluding Property from the Jackie Napolean Wilson Collection,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Christie's,,,,,,,,,,,,,"Montgomery, R.G.",,Fotograf:in,,"Wilson, Jackie Napolean",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Christie's,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,28,9,2001,,3,10,2001,Auktion,4,10,2001,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Christie's],"Post-War and Contemporary Art, Christie's, 10.11. - ..",Post-War and Contemporary Art,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,Malerei,,,,,,,,New York,4042011-5,,,,,,,Christie's,,,,,,,,,,,,,"Cappellazzo, Amy",,Veranstalter:in,,"Gorvy, Brett",,Veranstalter:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Christie's,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,11,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,Malerei,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Christie's],"Photographs, Christie's east, 4.6.1999 - 8.6.1998",Photographs,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Christie's east,,,,,,,,,,,,,"Steichen, Edward",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Christie's east,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,4,6,1999,,8,6,1998,Auktion,9,6,1999,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Christie's],"19th & 20th Century Photographs, Christie's",19th & 20th Century Photographs,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Christie's,,,,,,,,,,,,,"Käsebier, Gertrude",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Christie's,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Auktion,28,10,1987,,,,,,,,,Auktion,29,10,1987,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"The Fashion Revolution 1950-1970, Staley Wise - Gallery, 10.9.2004 - 23.10.2004",The Fashion Revolution 1950-1970,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,9,2004,,23,10,2004,Vernissage,9,9,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Herb Ritts Body 1984-1999, Staley Wise - Gallery, 4.2.2005 - 19.3.2005",Herb Ritts Body 1984-1999,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Ritts, Herb",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,4,2,2005,,19,3,2005,Vernissage,3,2,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Slim Aarons - Once Upon A Time, Staley Wise - Gallery, 7.11.2004 - 3.1.2004",Slim Aarons - Once Upon A Time,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Aarons, Slim",,Fotograf:in,,"Abrams, Harry N.",,Veranstalter:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,Getty Images,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,7,11,2004,,3,1,2004,Vernissage,6,11,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"1983 Revisited, Staley Wise - Gallery, 6.5.2005 - 25.6.2005",1983 Revisited,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Dahl-Wolfe, ?",,Fotograf:in,,"Doisneau, ?",,Fotograf:in,"Horst, ?",Fotograf:in,"Kertesz, ?",Fotograf:in,"Newman, Arnold",Fotograf:in,"Newton, Helmut",Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,5,2005,,25,6,2005,Vernissage,5,5,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"What a life!: Photographs from the Life Magazine archive, Staley Wise - Gallery, 3.2.2006 - 11.3.2006",What a life!,Photographs from the Life Magazine archive,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,2,2006,,11,3,2006,Vernissage,2,2,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"""Stills To Cinema"" - Jerry Schatzberg, Staley Wise - Gallery, 12.9.1996 - 5.10.1996","""Stills To Cinema"" - Jerry Schatzberg",,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Schatzberg, Jerry",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,12,9,1996,,5,10,1996,Vernissage,11,9,1996,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Reflections Lillian Bassman, Staley Wise - Gallery, 22.9.2006 - 28.10.2006",Reflections Lillian Bassman,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Bassman, Lillian",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,22,9,2006,,28,10,2006,Vernissage,21,9,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Rico Puhlmann - A Fashion Legacy, Staley Wise - Gallery, 25.3.2005 - 23.4.2005",Rico Puhlmann - A Fashion Legacy,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Puhlmann, Rico",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,25,3,2005,,23,4,2005,Vernissage,24,3,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Encounters - Denis Piel, Staley Wise - Gallery, 2.5.2003 - 31.5.2003",Encounters - Denis Piel,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Piel, Denis",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,2,5,2003,,31,5,2003,Vernissage,1,5,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Ellen von Unwerth - Revenge, Staley Wise - Gallery, 21.3.2003 - 19.4.2003",Ellen von Unwerth - Revenge,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"von Unwerth, Ellen",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,21,3,2003,,19,4,2003,Vernissage,20,3,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Deborah Turbeville - Elements of Style, Staley Wise - Gallery, 31.1.2003 - 25.3.2003",Deborah Turbeville - Elements of Style,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Turbeville, Deborah",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,31,1,2003,,25,3,2003,Vernissage,30,1,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"20th Century Women, Staley Wise - Gallery, 2.4.1993 - 22.5.1993",20th Century Women,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Huene, ?",,Fotograf:in,,"Naylar, Genevieve",,Fotograf:in,"Newton, Helmut",Fotograf:in,"Ritts, Herb",Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,2,4,1993,,22,5,1993,Vernissage,1,4,1993,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Antonio - Fashion Drawings and Photography 60's, 70's, 80's, Staley Wise - Gallery, 10.3.2000 - 8.4.2000","Antonio - Fashion Drawings and Photography 60's, 70's, 80's",,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"?, Antonio",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,3,2000,,8,4,2000,Vernissage,9,3,2000,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Marcia Lippman - The Legacy of Madame Gres, Staley Wise - Gallery, 23.9.1994 - 29.10.1994",Marcia Lippman - The Legacy of Madame Gres,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Lippman, Marcia",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,23,9,1994,,29,10,1994,Vernissage,22,9,1994,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Chris von Wangenheim - Fashion and Portrait: Vintage Photographs, Staley Wise - Gallery, 23.9.1994 - 29.10.1994",Chris von Wangenheim - Fashion and Portrait,Vintage Photographs,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"von Wangenheim, Chris",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,23,9,1994,,29,10,1994,Vernissage,22,9,1994,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Joel Grey, Photographer, Staley Wise - Gallery, 5.6.2003 - 3.7.2003","Joel Grey, Photographer",,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Grey, Joel",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,6,2003,,3,7,2003,Vernissage,5,6,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Roxanne Lowit - Moments, Staley Wise - Gallery, 29.10.1993 - 27.11.1993",Roxanne Lowit - Moments,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Lowit, Roxanne",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,29,10,1993,,27,11,1993,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Bob Willoughby: Persistence of Vision-Photographs From the Film Set 1953-1971, Staley Wise - Gallery, 28.4.1998 - 23.5.1998",Bob Willoughby,Persistence of Vision-Photographs From the Film Set 1953-1971,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Willoughby, Bob",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,28,4,1998,,23,5,1998,Vernissage,28,4,1998,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Horst Hoyningen-Huene - Shadow and Light, Staley Wise - Gallery, 20.12.2001 - 2.2.2002",Horst Hoyningen-Huene - Shadow and Light,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Hoyningen-Huene, Horst",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,20,12,2001,,2,2,2002,Vernissage,19,12,2001,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Cecil Beaton, Staley Wise - Gallery, 13.3.1998 - 18.4.1998",Cecil Beaton,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Beaton, Cecil",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,3,1998,,18,4,1998,Vernissage,12,3,1998,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Harry Benson, Staley Wise - Gallery, 7.11.2008 - 3.1.2009",Harry Benson,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Benson, Harry",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,11,2008,,3,1,2009,Vernissage,6,11,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Ellen von Unwerth - Fräulein, Staley Wise - Gallery, 11.12.2009 - 30.1.2010",Ellen von Unwerth - Fräulein,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"von Unwerth, Ellen",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,12,2009,,30,1,2010,Vernissage,10,12,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Lillian Basssman - 12 Platinum Prints, Staley Wise - Gallery, 14.2.2008 - 26.4.2008",Lillian Basssman - 12 Platinum Prints,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Bassman, Lillian",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,2,2008,,26,4,2008,Vernissage,14,2,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"That's Great! - Photographs by Ron Galella, Staley Wise - Gallery, 1.5.2008 - 7.6.2008",That's Great! - Photographs by Ron Galella,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Galella, Ron",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,1,5,2008,,7,6,2008,Vernissage,1,5,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Patrick Demarchelier: Part 1, Staley Wise - Gallery, 12.9.2008 - 25.10.2008",Patrick Demarchelier: Part 1,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Demarchelier, Patrick",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,12,9,2008,,25,10,2008,Vernissage,11,9,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Scavullo - Photographs 50 years, Staley Wise - Gallery, 10.10.1997 - 1.11.1997",Scavullo - Photographs 50 years,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Scavullo, ?",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,10,1997,,1,11,1997,Vernissage,9,10,1997,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"An Exhibition of Vintage Prints: 19th and 20th Century Photographs, Staley Wise - Gallery, 6.3.1987 - 18.4.1987",An Exhibition of Vintage Prints,19th and 20th Century Photographs,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Blumenfeld, Erwin",,Künstler:in,,"Dahl-Wolfe, Louise",,Künstler:in,"De Meyer, ?",Künstler:in,"Hoyningen-Huene, ?",Künstler:in,"Miller, Lee",Künstler:in,"Steichen, ?",Künstler:in,"Sutcliffe, ?",Künstler:in,"Ray, Man",Künstler:in,"Genthe, ?",Künstler:in,"Kollar, ?",Künstler:in,"Platt-Lynes, ?",Künstler:in,"D'ora, ?",Künstler:in,"Bull, ?",Künstler:in,"Richee, ?",Künstler:in,"Hurrell, ?",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,3,1987,,18,4,1987,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"The Photographic Art of Hoyningen-Huene: An Exhibition of Photographs 1920-1940, Staley Wise - Gallery, 12.11.1986 - 6.12.1986",The Photographic Art of Hoyningen-Huene,An Exhibition of Photographs 1920-1940,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Hoyningen-Huene, Horst",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,"Rizzoli INternational Publications, Inc.",,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,12,11,1986,,6,12,1986,Vernissage,17,11,1986,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Patrick Demarchelier: Part II, Staley Wise - Gallery, 27.9.2013 - 30.11.2013",Patrick Demarchelier: Part II,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Demarchelier, Patrick",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,27,9,2013,,30,11,2013,Vernissage,26,9,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Lillian Bassman - 1917-2012: Lingerie, Staley Wise - Gallery, 13.4.2012 - 26.5.2012",Lillian Bassman - 1917-2012,Lingerie,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Bassman, Lillian",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,4,2012,,26,5,2012,Vernissage,12,4,2012,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Ron Galella - Pop, Rock & Dance, Staley Wise - Gallery, 13.12.2013 - 25.1.2014","Ron Galella - Pop, Rock & Dance",,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Galella, Ron",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,12,2013,,25,1,2014,Vernissage,12,12,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Bert Stern: Original Mad Man, Staley Wise - Gallery, 5.4.2013 - 18.5.2013",Bert Stern,Original Mad Man,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,Medienkunst,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Stern, Bert",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,4,2013,,18,5,2013,Vernissage,4,4,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,Medienkunst,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Herbert Matter - Vintage Photographs 1937-1979, Staley Wise - Gallery, 3.11.1995 - 1.12.1995",Herbert Matter - Vintage Photographs 1937-1979,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Matter, Bert",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,11,1995,,1,12,1995,Vernissage,2,11,1995,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Music and Fashion 1965-1975, Staley Wise - Gallery, 18.5.2007 - 30.6.2007",Music and Fashion 1965-1975,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Rothschild, Amalie R.",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,18,5,2007,,30,6,2007,Vernissage,17,5,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Disfarmer, Staley Wise - Gallery, 5.5. - 10.6.",Disfarmer,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Disfarmer, ?",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,5,,,10,6,,Vernissage,11,5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Genevieve Naylor - 40 years of photography, Staley Wise - Gallery, 3.2.1995 - 18.3.1995",Genevieve Naylor - 40 years of photography,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Naylor, Genevieve",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,2,1995,,18,3,1995,Vernissage,2,2,1995,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Bob Richardson - Beyond Cool, Staley Wise - Gallery, 7.6.1996 - 6.7.1996",Bob Richardson - Beyond Cool,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Richardson, Bob",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,Big Magazine,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,7,6,1996,,6,7,1996,Vernissage,6,6,1996,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Color of Fashion: Photographs 1960-1995, Staley Wise - Gallery, 31.3.1995 - 29.4.1995",Color of Fashion,Photographs 1960-1995,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,31,3,1995,,29,4,1995,Vernissage,30,3,1995,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"The Nude Interpreted, Staley Wise - Gallery, 17.2.2012 - 7.4.2012",The Nude Interpreted,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Maser, Wayne",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,17,2,2012,,7,4,2012,Vernissage,16,2,2012,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Jim Marshall and Timothy White - Match Prints, Staley Wise - Gallery, 26.3.2010 - 24.4.2010",Jim Marshall and Timothy White - Match Prints,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Marshall, Jim",,Fotograf:in,,"White, Timothy",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,26,3,2010,,24,4,2010,Vernissage,25,3,2010,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Buds, Blooms & Blossoms, Staley Wise - Gallery, 3.5.2002 - 15.6.2002","Buds, Blooms & Blossoms",,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,5,2002,,15,6,2002,Vernissage,2,5,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Max Dupain's Australia: photographs 1928-1987, Staley Wise - Gallery, 6.11.1987 - 5.12.1987",Max Dupain's Australia,photographs 1928-1987,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Dupain, Max",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,11,1987,,5,12,1987,Vernissage,5,11,1987,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Chords No. 1-17, Staley Wise - Gallery, 28.6.2002 - 26.7.2002",Chords No. 1-17,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Krisár, Anders",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,28,6,2002,,26,7,2002,Vernissage,27,6,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Magnum Style, Staley Wise - Gallery, 23.4.2004 - 29.5.2004",Magnum Style,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,23,4,2004,,29,5,2004,Vernissage,22,4,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Helmut Newton - Portraits, Fashion and Nudes, Staley Wise - Gallery, 14.9.2001 - 27.10.2001","Helmut Newton - Portraits, Fashion and Nudes",,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Newton, Helmut",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,9,2001,,27,10,2001,Vernissage,13,9,2001,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"David Seidner 1957-1999, Staley Wise - Gallery, 16.9.1999 - 9.10.1999",David Seidner 1957-1999,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Seidner, David",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,16,9,1999,,9,10,1999,Vernissage,16,9,1999,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Harry Benson, Fifty Years in Pictures, Staley Wise - Gallery, 2.11.2001 - 1.12.2001","Harry Benson, Fifty Years in Pictures",,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Benson, Harry",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,"Harry N. Abrams, INc.",,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,2,11,2001,,1,12,2001,Vernissage,1,11,2001,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Genevieve Naylor - Brazilian Photographs, 1940-42, Staley Wise - Gallery, 2.11.2001 - 1.12.2001","Genevieve Naylor - Brazilian Photographs, 1940-42",,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Naylor, Genevieve",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,2,11,2001,,1,12,2001,Vernissage,1,11,2001,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Herbert Matter - Giacometti: A Collaboration, Staley Wise - Gallery, 14.9.2001 - 27.10.2001",Herbert Matter - Giacometti,A Collaboration,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Matter, Herbert",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,9,2001,,27,10,2001,Vernissage,13,9,2001,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"New York Living Rooms: Dominique Nabakov - The Overlook Press, Staley Wise - Gallery, 6.11.1998 - 5.12.1998",New York Living Rooms,Dominique Nabakov - The Overlook Press,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Sachs, Tom",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,11,1998,,5,12,1998,Vernissage,5,11,1998,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Norman Parkinson, Staley Wise - Gallery, 6.11.1998 - 5.12.1998",Norman Parkinson,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Parkinson, Norman",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,11,1998,,5,12,1998,Vernissage,5,11,1998,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Helmut Newton - Private Property: Photographs 1975-1983, Staley Wise - Gallery, 30.1.1987 - 28.2.1987",Helmut Newton - Private Property,Photographs 1975-1983,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Newton, Helmut",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,30,1,1987,,28,2,1987,Vernissage,29,1,1987,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Priscilla Rattazzi - Selected Photographs 1975-2013, Staley Wise - Gallery, 31.1.2014 - 22.2.2014",Priscilla Rattazzi - Selected Photographs 1975-2013,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Rattazzi, Priscilla",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,31,1,2014,,22,2,2014,Vernissage,30,1,2014,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"The Olympics: The Fire Within: Salt Lake 2002, Staley Wise - Gallery, 1.11.2002 - 30.11.2002",The Olympics,The Fire Within: Salt Lake 2002,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Metzner, Sheila",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,1,11,2002,,30,11,2002,Vernissage,31,10,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"The Golden Age of Hollywood: Photographs 1930's-1940's, Staley Wise - Gallery, 3.10.1986 - 1.11.1986",The Golden Age of Hollywood,Photographs 1930's-1940's,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Allan, Ted",,Fotograf:in,,"Coburn, Bob",,Fotograf:in,"Willinger, Laszlo",Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,10,1986,,1,11,1986,Vernissage,2,10,1986,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Louise Dahl-Wolfe - Form and Fashion: Photographs 1930's-1950's, Staley Wise - Gallery, 30.9. - 12.11.",Louise Dahl-Wolfe - Form and Fashion,Photographs 1930's-1950's,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Dahl-Wolfe, Louise",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,30,9,,,12,11,,Vernissage,29,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"de Meyer - Portraits of Fashion: Baron de Meyer Vintage Photographs 1910-1920, Staley Wise - Gallery, 13.4.1994 - 12.5.1994",de Meyer - Portraits of Fashion,Baron de Meyer Vintage Photographs 1910-1920,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"de Meyer, Baron",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,4,1994,,12,5,1994,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Edward Steichen - Master Photographer 1900's-1950's, Staley Wise - Gallery, 12.12.1987 - 24.1.1987",Edward Steichen - Master Photographer 1900's-1950's,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Steichen, Edward",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,12,12,1987,,24,1,1987,Vernissage,11,12,1987,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"The Art of Horst, Staley Wise - Gallery, 28.1.2000 - 4.3.2000",The Art of Horst,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,28,1,2000,,4,3,2000,Vernissage,27,1,2000,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"form and fashion, Staley Wise - Gallery, 10.6.2011 - 12.8.2011",form and fashion,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Hoyningen-Huene, ?",,Fotograf:in,,"Markus, Kurt",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,6,2011,,12,8,2011,Vernissage,9,6,2011,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Michael Dweck - Mermaids 2006-2008, Staley Wise - Gallery, 19.6.2008 - 6.9.2008",Michael Dweck - Mermaids 2006-2008,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Dweck, Michael",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,19,6,2008,,6,9,2008,Vernissage,19,6,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Celebrating 25 Years of Staley Wise with the 100th Birthday of Horst, Staley Wise - Gallery, 1.12.2006 - 27.1.2007",Celebrating 25 Years of Staley Wise with the 100th Birthday of Horst,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,1,12,2006,,27,1,2007,Vernissage,30,11,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Mary Ellen Mark - Seen Behind the Scene, Staley Wise - Gallery, 9.1.2009 - 14.2.2009",Mary Ellen Mark - Seen Behind the Scene,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Mark, Mary Ellen",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,1,2009,,14,2,2009,Vernissage,8,1,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Harry Benson - Get the Picture, Staley Wise - Gallery, 16.12.2017 - 28.1.2017",Harry Benson - Get the Picture,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Benson, Harry",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,16,12,2017,,28,1,2017,Vernissage,15,12,2016,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Staley Wise Gallery],"Harry Benson - Work, Staley Wise - Gallery, 14.9.2012 - 27.10.2012",Harry Benson - Work,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Staley Wise Gallery,,,,,,,,,,,,,"Benson, Harry",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley Wise - Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,9,2012,,27,10,2012,Vernissage,13,9,2012,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Adam Fuss, Cheim & Read, 16.10.2003 - 15.11.2003",Adam Fuss,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Fuss, Adam",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,16,10,2003,,15,11,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Dona Nelson - Tactile Image, Cheim & Read, 7.1.2003 - 8.2.2003",Dona Nelson - Tactile Image,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Nelson, Dona",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,1,2003,,8,2,2003,Vernissage,7,1,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Simple Marks, Cheim & Read, 23.7.2003 - 29.8.2003",Simple Marks,,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,,Fotograf,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Burton, Richmond",,Künstler:in,,"Bourgeois, Louise",,Künstler:in,"Benglis, Lynda",Künstler:in,"Fishman, Louise",Künstler:in,"Fyfe, Joe",Künstler:in,"Mitchell, Joan",Künstler:in,"Pierson, Jack",Künstler:in,"Piffaretti, Bernard",Künstler:in,"Steir, Pat",Künstler:in,"Twombly, Cy",Künstler:in,"Uslé, Juan",Künstler:in,"Viallat, Claude",Künstler:in,"Zitko, Otto",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,23,7,2003,,29,8,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,Fotograf,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Ingo Meller, Cheim & Read, 11.2.2003 - 15.3.2003",Ingo Meller,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Meller, Ingo",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,2,2003,,15,3,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Otto Zitko - an installation, Cheim & Read, 11.2.2003 - 15.3.2003",Otto Zitko - an installation,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,Installation,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Zitko, Otto",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,2,2003,,15,3,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Jenny Holzer and James Carpenter - For 7 World Trade, Cheim & Read, 22.5. - ..",Jenny Holzer and James Carpenter - For 7 World Trade,,,,,Gruppenausstellung,Sonderausstellung,,,,,Installation,,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Holzer, Jenny",,Künstler:in,,"Carpenter, James",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,Silverstein Properties,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,22,5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Donald Baechler - Sculpture, Cheim & Read, 13.1.2005 - 12.2.2005",Donald Baechler - Sculpture,,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Baechler, Donald",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,1,2005,,12,2,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Bildhauerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"McDermott & McGough - A True Story Based on Lies, Cheim & Read, 12.1.2006 - 11.2.2006",McDermott & McGough - A True Story Based on Lies,,,,,Gruppenausstellung,Sonderausstellung,,,,,Grafik,,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"McDermott, ?",,Künstler:in,,"McGough, ?",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,12,1,2006,,11,2,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Louise Fishman - ""My City"" Recent Paintings and Drawings, Cheim & Read, 22.4.2003 - 24.5.2003","Louise Fishman - ""My City"" Recent Paintings and Drawings",,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,Grafik,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Fishman, Louise",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,22,4,2003,,24,5,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Monique Prieto - New Paintings, Cheim & Read, 10.9.2005 - 15.10.2005",Monique Prieto - New Paintings,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Prieto, Monique",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,9,2005,,15,10,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Lynda Bengils - The Graces, Cheim & Read, 10.9.2005 - 15.10.2005",Lynda Bengils - The Graces,,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Benglis, Lynda",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,9,2005,,15,10,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Bildhauerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Jean-Michel Basquiat - In Word Only, Cheim & Read, 17.2.2005 - 26.3.2005",Jean-Michel Basquiat - In Word Only,,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,Malerei,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Basquiat, Jean-Michel",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,17,2,2005,,26,3,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Pat Steir - Moons and a River, Cheim & Read, 31.3.2005 - 7.5.2005",Pat Steir - Moons and a River,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Steir, Pat",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,31,3,2005,,7,5,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Soutine and Modern Art: The New Landscape, The New Still Life, Cheim & Read, 22.6.2006 - 9.9.2006",Soutine and Modern Art,"The New Landscape, The New Still Life",,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Soutine, Chaim",,Künstler:in,,"Arikha, Avigdor",,Künstler:in,"Auerbach, Frank",Künstler:in,"Baselitz, Georg",Künstler:in,"Bourgeois, Louise",Künstler:in,"Brodie, Gandy",Künstler:in,"de Kooning, Willem",Künstler:in,"Diebenkorn, Richard",Künstler:in,"Dubuffet, Jean",Künstler:in,"Fishman, Louise",Künstler:in,"Freud, Lucian",Künstler:in,"Guston, Philip",Künstler:in,"Jensen, Bill",Künstler:in,"Kossoff, Leon",Künstler:in,"Mitchell, Joan",Künstler:in,"Neel, Alice",Künstler:in,"Pasqua, Philippe",Künstler:in,"Pollock, Jackson",Künstler:in,"Quintero, Daniel",Künstler:in,"Resnick, Milton",Künstler:in,"Rothenberg, Susan",Künstler:in,"Shapiro, Joel",Künstler:in,"Tworkov, Jack",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,22,6,2006,,9,9,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Louise Fishman, Cheim & Read, 15.2.2006 - 25.3.2006",Louise Fishman,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Fishman, Louise",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,15,2,2006,,25,3,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Joan Mitchell - Foundation, Cheim & Read",Joan Mitchell - Foundation,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Mitchell, Joan",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Marvin Israel (1924-84) - Black Paintings, Cheim & Read, 28.6.2005 - 2005.3.9",Marvin Israel (1924-84) - Black Paintings,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Israel, Marvin",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,28,6,2005,,2005,3,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"William Eggleston - Nightclub Portraits, 1973, Cheim & Read, 3.9.2005 - 28.6.2005","William Eggleston - Nightclub Portraits, 1973",,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Eggleston, William",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,9,2005,,28,6,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Joan Mitchell - Frémicourt Paintings 1960-62, Cheim & Read, 10.5.2005 - 25.6.2005",Joan Mitchell - Frémicourt Paintings 1960-62,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Mitchell, Joan",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,5,2005,,25,6,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Lynda Benglis - Louise Fishman, Cheim & Read",Lynda Benglis - Louise Fishman,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,Bildhauerei,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Benglis, Lynda",,Künstler:in,,"Fishman, Louise",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"I Am Richmond Burton: Paintings, Cheim & Read, 25.4.2001 - ..",I Am Richmond Burton,Paintings,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Burton, Richmond",,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,25,4,2001,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Paul Morrison, Cheim & Read, 14.4.2004 - 28.5.2004",Paul Morrison,,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Morrison, Paul",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,4,2004,,28,5,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"I Am The Walrus, Cheim & Read, 10.6.2004 - 30.7.2004",I Am The Walrus,,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Acconci, Vito",,Künstler:in,,"Baechler, Donald",,Künstler:in,"Basquiat, Jean-Michel",Künstler:in,"Bickerton, Ashley",Künstler:in,"Breuning, Olaf",Künstler:in,"Bock, John",Künstler:in,"Cattelan, Maurizio",Künstler:in,"Horn, Roni",Künstler:in,"Hurson, Michael",Künstler:in,"Kippenberger, Martin",Künstler:in,"Landers, Sean",Künstler:in,"Matelli, Tony",Künstler:in,"McCarthy, Dan",Künstler:in,"McCarthy, Paul",Künstler:in,"McDermott, ?",Künstler:in,"McGough, ?",Künstler:in,"Mendieta, Anna",Künstler:in,"Nauman, Bruce",Künstler:in,"Pierson, Jack",Künstler:in,"Prince, Richard",Künstler:in,"Rosenberg, Aura",Künstler:in,"Rondinone, Ugo",Künstler:in,"Salle, David",Künstler:in,"Sherman, Cindy",Künstler:in,"Simmons, Laurie",Künstler:in,"Sweeney, Spencer",Künstler:in,"Wachtel, Julia",Künstler:in,"Waters, John",Künstler:in,"Wool, Christopher",Künstler:in,"Avgikos, Jan",Kurator:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,6,2004,,30,7,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Bettina Rheims - Chambre Close, 1991, Cheim & Read, 15.10.2002 - 16.11.2002","Bettina Rheims - Chambre Close, 1991",,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Rheims, Bettina",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,15,10,2002,,16,11,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Lynda Benglis - Quartered Meteor, 1969, Cheim & Read, 15.10.2002 - 16.11.2002","Lynda Benglis - Quartered Meteor, 1969",,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Benglis, Lynda",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,15,10,2002,,16,11,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Bildhauerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Claude Viallat, Cheim & Read, 12.9.2002 - 12.10.2002",Claude Viallat,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Viallat, Claude",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,12,9,2002,,12,10,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Jenny Holzer - OH, Cheim & Read, 16.10.2001 - ..",Jenny Holzer - OH,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Holzer, Jenny",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,16,10,2001,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Louise Bourgeois 2001, Cheim & Read, 20.11.2001 - 5.1.2002",Louise Bourgeois 2001,,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Bourgeois, Louise",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,20,11,2001,,5,1,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Bildhauerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Liquid Properties, Cheim & Read, 6.7.2001 - 3.8.2001",Liquid Properties,,,,,Gruppenausstellung,Sonderausstellung,,,,,Bildhauerei,,Malerei,,Grafik,,Installation,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Benglis, Lynda",,Künstler:in,,"Bourgeois, Louise",,Künstler:in,"Burton, Richmond",Künstler:in,"Fuss, Adam",Künstler:in,"Heilmann, Mary",Künstler:in,"Hines, David",Künstler:in,"Hume, Gary",Künstler:in,"Nelson, Dona",Künstler:in,"Pierson, Jack",Künstler:in,"Steir, Pat",Künstler:in,"Usle, Juan",Künstler:in,"Warhol, Andy",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,7,2001,,3,8,2001,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Bildhauerei,Malerei,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Bernard Piffaretti, Cheim & Read, 8.1.2002 - 9.2.2002",Bernard Piffaretti,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Piffaretti, Bernard",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,1,2002,,9,2,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Joan Mitchell - The Presence of Absence, Cheim & Read, 20.6.2002 - 18.8.2002",Joan Mitchell - The Presence of Absence,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Mitchell, Joan",,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,20,6,2002,,18,8,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Juan Uslé, Cheim & Read, 30.4.2002 - 1.6.2002",Juan Uslé,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Uslé, Juan",,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,30,4,2002,,1,6,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"William Eggleston - recent work, Cheim & Read, 1.3.2001 - ..",William Eggleston - recent work,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Eggleston, William",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,1,3,2001,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Robert Mapplethorpe - Autoportrait Polaroids 1972-1974, Cheim & Read, 28.4.2000 - 10.6.2000",Robert Mapplethorpe - Autoportrait Polaroids 1972-1974,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Mapplethorpe, Robert",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,American Foundation for AIDS Research - amfAR,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,28,4,2000,,10,6,2000,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Alessandro Raho - new paintings, Cheim & Read, 10.9.2003 - 11.10.2003",Alessandro Raho - new paintings,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Raho, Alessandro",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,9,2003,,11,10,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"the first Photography Portfolio to benefit the American Foundation for AIDS Research amfAR, Cheim & Read, 10.9.2003 - 11.10.2003",the first Photography Portfolio to benefit the American Foundation for AIDS Research amfAR,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,,,,,,,,,,,,,"Pierson, Jack",,Kurator:in,,"Armstrong, David",,Künstler:in,"Barney, Tina",Künstler:in,"Bey, Dawoud",Künstler:in,"Brown, Cecily",Künstler:in,"Burke, Bill",Künstler:in,"Cesarco, Alejandro",Künstler:in,"Craig-Martin, Jessica",Künstler:in,"Eggleston, William",Künstler:in,"Karella, Marina",Künstler:in,"Klein, Steven",Künstler:in,"McDermott, David",Künstler:in,"McCough, Peter",Künstler:in,"McGinley, Ryan",Künstler:in,"Minter, Marilyn",Künstler:in,"Pfahler, Kembra",Künstler:in,"Pierson, Jack",Künstler:in,"Shore, Steven",Künstler:in,"Taylor-Wood, Steven",Künstler:in,"Weber, Bruce",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,9,2003,,11,10,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Don Bachardy - Christopher Isherwood; Last Drawings, Cheim & Read, 1.6.2009 - 2.7.2009",Don Bachardy - Christopher Isherwood; Last Drawings,,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,4021845-4,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,10091432-9,,,,,,,,,,,,"Bachardy, Don",123221749,Grafiker:in,,"Isherwood, Christopher",118710958,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,1,6,2009,,2,7,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Louise Bourgeois - The Reticent Child, Cheim & Read, 21.10.2004 - 31.12.2004",Louise Bourgeois - The Reticent Child,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,10091432-9,,,,,,,,,,,,"Bourgeois, Louise",118943375,Bildhauer:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,21,10,2004,,31,12,2004,Vernissage,21,10,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"The Female Gaze - Women Look At Women, Cheim & Read, 25.6.2009 - 9.12.2009",The Female Gaze - Women Look At Women,,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,4037220-0,Fotografie,4045895-7,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,10091432-9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,25,6,2009,,9,12,2009,Vernissage,25,6,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,Fotografie,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Jack Pierson - Abstracts, Cheim & Read, 8.10.2009 - 14.11.2009",Jack Pierson - Abstracts,,,,,Einzelausstellung,Sonderausstellung,,,,,Objektkunst,4131740-3,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,10091432-9,,,,,,,,,,,,"Pierson, Jack",119304457,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,10,2009,,14,11,2009,Vernissage,8,10,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Objektkunst,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"The Sum of its Parts, Cheim & Read, 8.1.2008 - 2.2.2008",The Sum of its Parts,,,,,Gruppenausstellung,Sonderausstellung,,,,,Objektkunst,4131740-3,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,10091432-9,,,,,,,,,,,,"Benglis, Lynda",118850563,Künstler:in,,"Bourgeois, Louise",118943375,Künstler:in,"Fernandez, Teresita",Künstler:in,"Fuss, Adam",Künstler:in,Gilbert & George,Künstler:in,"Holzer, Jenny",Künstler:in,"Horn, Roni",Künstler:in,"Kounellis, Jannis",Künstler:in,"Naumann, Bruce",Künstler:in,"Pierson, Jack",Künstler:in,"Sonsini, John",Künstler:in,"Warhol, Andy",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,1,2008,,2,2,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Objektkunst,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Joan Mitchell - A Survey of Works on Paper 1956-1992, Cheim & Read, 10.5.2007 - 16.6.2007",Joan Mitchell - A Survey of Works on Paper 1956-1992,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,10091432-9,,,,,,,,,,,,"Mitchell, Joan",119068656,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,5,2007,,16,6,2007,Vernissage,10,5,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"I Am as You Will Be: The Skeleton in Art, Cheim & Read, 20.9.2007 - 3.11.2007",I Am as You Will Be,The Skeleton in Art,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,4037220-0,Grafik,4021845-4,Plastik,4046277-8,,,,,New York,4042011-5,,,,,,,Cheim & Read,10091432-9,,,,,,,,,,,,"Alÿs, Francis",119546736,Künstler:in,,"Baechler, Donald",120856263,Künstler:in,"Barney, Matthew",Künstler:in,"Basquiat, jean-Michel",Künstler:in,"Benglis, Lynda",Künstler:in,"Borremans, Michael",Künstler:in,"Bourgeois, Louise",Künstler:in,"Broodthaers, Marcel",Künstler:in,"Dali, Salvador",Künstler:in,"Delvaux, Paul",Künstler:in,"Delvoye, Wim",Künstler:in,"Dumas, Marlene",Künstler:in,"Ensor, James",Künstler:in,"Fabre, Jan",Künstler:in,"Filomeno, Angelo",Künstler:in,"Flexner, Roland",Künstler:in,"Fritsch, Katharina",Künstler:in,"Fuss, Adam",Künstler:in,"Hirst, Damien",Künstler:in,"Holzer, Jenny",Künstler:in,Lady Pink,Künstler:in,"Kounellis, Jannis",Künstler:in,"Levine, Sherrie",Künstler:in,"Matelli, Tony",Künstler:in,McDermott & McCough,Künstler:in,"Morris, Robert",Künstler:in,"Munch, Edvard",Künstler:in,"Neel, Alice",Künstler:in,"Picasso, Pablo",Künstler:in,"Pierson, Jack",Künstler:in,"Polke, Sigmar",Künstler:in,"Richter, Gerhard",Künstler:in,"Rops, Félicien",Künstler:in,"Tuymans, Luc",Künstler:in,"van Oost, Jan",Künstler:in,"Warhol, Andy",Künstler:in,"McGough, Peter",119452642,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,McDermott & McCough,,132431006,Künstlerkollektiv,,,,,,,,,,,,,,,,,,,,,20,9,2007,,3,11,2007,Vernissage,20,9,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,Grafik,Plastik,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Pat Steir, Cheim & Read, 9.11.2007 - 22.12.2007",Pat Steir,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,10091432-9,,,,,,,,,,,,"Steir, Pat",11930659X,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,11,2007,,22,12,2007,Vernissage,9,11,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Milton Resnick - A Question of Seeing: Paintings 1959-1963, Cheim & Read, 1.5.2008 - 7.6.2008",Milton Resnick - A Question of Seeing,Paintings 1959-1963,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,10091432-9,,,,,,,,,,,,"Resnick, Milton",17426254X,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,1,5,2008,,7,6,2008,Vernissage,1,5,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Jannis Kounellis, Cheim & Read, 8.11.2007 - 6.1.2007",Jannis Kounellis,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,1228235120,Objektkunst,4131740-3,Malerei,4037220-0,,,,,New York,4042011-5,,,,,,,Cheim & Read,10091432-9,,,,,,,,,,,,"Kounellis, Jannis",119018276,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,11,2007,,6,1,2007,Vernissage,8,11,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,Objektkunst,Malerei,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Jonathan Lasker, Cheim & Read, 29.3.2007 - 5.5.2007",Jonathan Lasker,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,10091432-9,,,,,,,,,,,,"Lasker, Jonathan",119100495,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,29,3,2007,,5,5,2007,Vernissage,29,3,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Juan Uslé - Brezales, Cheim & Read, 7.2.2008 - 15.3.2008",Juan Uslé - Brezales,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,10091432-9,,,,,,,,,,,,"Uslé, Juan",119275309,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,2,2008,,15,3,2008,Vernissage,7,2,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Cheim & Read],"Louise Bourgeois - Echo, Cheim & Read, 9.9.2008 - 1.11.2008",Louise Bourgeois - Echo,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Cheim & Read,10091432-9,,,,,,,,,,,,"Bourgeois, Louise",118943375,Bildhauer:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cheim & Read,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,9,2008,,1,11,2008,Vernissage,9,9,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Hank O'Neal - The Ghosts of Harlem: A selection of photographs of Jazz legends, Howard Greenberg Gallery, 22.5.2009 - 11.7.2009",Hank O'Neal - The Ghosts of Harlem,A selection of photographs of Jazz legends,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Howard Greenberg Gallery (New York, NY)",5171672-0,,,,,,,,,,,,"O'Neal, Hank",136326536,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,22,5,2009,,11,7,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Saul Leiter - Early Color, Howard Greenberg Gallery, 9.12.2005 - 21.1.2006",Saul Leiter - Early Color,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Howard Greenberg Gallery (New York, NY)",5171672-0,,,,,,,,,,,,"Leiter, Saul",131634240,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,12,2005,,21,1,2006,Vernissage,8,12,2005,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"James Van Der Zee - Vintage Photographs, Howard Greenberg Gallery, 11.3.1994 - 30.4.1994",James Van Der Zee - Vintage Photographs,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Howard Greenberg Gallery (New York, NY)",5171672-0,,,,,,,,,,,,"Van der Zee, James",119182394,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,3,1994,,30,4,1994,Vernissage,12,3,1994,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"All About Abbott - Berenice 1927-1955, Howard Greenberg Gallery, 15.9.2006 - 4.11.2006",All About Abbott - Berenice 1927-1955,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Howard Greenberg Gallery (New York, NY)",5171672-0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,Commerce Graphics,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,15,9,2006,,4,11,2006,Vernissage,14,9,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Rebecca Lepkoff - Signs of Life, Howard Greenberg Gallery, 22.5.2009 - 11.7.2009",Rebecca Lepkoff - Signs of Life,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Howard Greenberg Gallery (New York, NY)",5171672-0,,,,,,,,,,,,"Lepkoff, Rebecca",122953398,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,22,5,2009,,11,7,2009,Vernissage,21,5,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Dennis Stock - Altered States, Howard Greenberg Gallery, 22.5.2009 - 11.7.2009",Dennis Stock - Altered States,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Howard Greenberg Gallery (New York, NY)",5171672-0,,,,,,,,,,,,"Stock, Dennis",11882175X,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,22,5,2009,,11,7,2009,Vernissage,21,5,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Martin Munkacsi - Vitality, Howard Greenberg Gallery, 20.3.2009 - 16.5.2009",Martin Munkacsi - Vitality,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Howard Greenberg Gallery (New York, NY)",5171672-0,,,,,,,,,,,,"Munkacsi, Martin",119306581,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,20,3,2009,,16,5,2009,Vernissage,19,3,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +https://www.howardgreenberg.com/exhibitions/photographers-of-japanese-descent,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Photographers of Japanese Descent: Araki, Yamawaki, Toda, Hosoe, Izu, Matsumoto, Ueda, Howard Greenberg Gallery, 14.3.2008 - 3.5.2008",Photographers of Japanese Descent,"Araki, Yamawaki, Toda, Hosoe, Izu, Matsumoto, Ueda",,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Howard Greenberg Gallery (New York, NY)",5171672-0,,,,,,,,,,,,"Araki, Nobuyoshi",119093693,Fotograf:in,,"Yamawaki, Iwao",121808785,Fotograf:in,Toda,Fotograf:in,"Hosoe, Eikoh",Fotograf:in,"Izu, Kendro",Fotograf:in,"Matsumoto, Tosh",Fotograf:in,"Ueda, Shōji",Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,3,2008,,3,5,2008,Vernissage,17,3,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Home on the Road - Marc Riboud: An Intrepid Photographer, Howard Greenberg Gallery, 25.1.2008 - 8.3.2008",Home on the Road - Marc Riboud,An Intrepid Photographer,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Howard Greenberg Gallery (New York, NY)",5171672-0,,,,,,,,,,,,"Riboud, Marc",119543850,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,25,1,2008,,8,3,2008,Vernissage,24,1,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Kenro Izu - Stillness, Howard Greenberg Gallery, 14.12.2007 - 19.1.2008",Kenro Izu - Stillness,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Howard Greenberg Gallery (New York, NY)",5171672-0,,,,,,,,,,,,"Izu, Kenro",122033817,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,12,2007,,19,1,2008,Vernissage,13,12,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Bruce Davidson - East 100th Street: The MoMa show as curated by John Szarkowski in 1970, Howard Greenberg Gallery, 5.11.2009 - 2.1.2010",Bruce Davidson - East 100th Street,The MoMa show as curated by John Szarkowski in 1970,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Howard Greenberg Gallery (New York, NY)",5171672-0,,,,,,,,,,,,"Szarkowski, John",129450804,Kurator:in,,"Davidson, Bruce",119308304,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,11,2009,,2,1,2010,Vernissage,4,11,2010,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Karl Blossfeldt, Edward Steichen, Dain Tasker, Edward Weston, Howard Greenberg Gallery, 10.11.2006 - 6.1.2007","Karl Blossfeldt, Edward Steichen, Dain Tasker, Edward Weston",,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,Fotografie,4045895-7,,,,,,,New York,4042011-5,,,,,,,"Howard Greenberg Gallery (New York, NY)",5171672-0,,,,,,,,,,,,"Blossfeldt, Karl",118511858,Künstler:in,,"Steichen, Edward",118617141,Künstler:in,"Tasker, Dain",Künstler:in,"Weston, Edward",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,11,2006,,6,1,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,Fotografie,,,,,Englisch,,,,,,,,,,, +https://www.howardgreenberg.com/artists/charles-jones,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Charles Jones, Howard Greenberg Gallery, 10.11.2006 - 6.1.2007",Charles Jones,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Howard Greenberg Gallery (New York, NY)",5171672-0,,,,,,,,,,,,"Jones, Charles",120657325,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,11,2006,,6,1,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +https://www.howardgreenberg.com/exhibitions/saul-leiter-women,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Saul Leiter: Women, Howard Greenberg Gallery, 9.5.2008 - 21.6.2008",Saul Leiter: Women,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Howard Greenberg Gallery (New York, NY)",5171672-0,,,,,,,,,,,,"Leiter, Saul",131634240,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,5,2008,,21,6,2008,Vernissage,8,5,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +https://www.howardgreenberg.com/exhibitions/times-square,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Times Square: William Klein, Robert Frank, Louis Faurer, Walker Evans, Leon Levinstein, Diane Arbus, Berenice Abbott, Ted Croner, Garry Winogrand & Weegee, Howard Greenberg Gallery, 9.5.2008 - 21.6.2008",Times Square,"William Klein, Robert Frank, Louis Faurer, Walker Evans, Leon Levinstein, Diane Arbus, Berenice Abbott, Ted Croner, Garry Winogrand & Weegee",,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Howard Greenberg Gallery (New York, NY)",5171672-0,,,,,,,,,,,,"Klein, William",118889435,Fotograf:in,,"Frank, Robert",118855387,Fotograf:in,"Faurer, Louis",Fotograf:in,"Evans, Walker",Fotograf:in,"Levinstein, Leon",Fotograf:in,"Arbus, Diane",Fotograf:in,"Abbott, Berenice",Fotograf:in,"Croner, Ted",Fotograf:in,"Winogrand, Garry",Fotograf:in,Weegee,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Howard Greenberg Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,5,2008,,21,6,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Kevin King - Dioramas, Jason McCoy Inc., 9.12.2008 - 24.1.2009",Kevin King - Dioramas,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Jason McCoy Inc.,"1,05E+09",,,,,,,,,,,,"King, Kevin",1026236169,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Jason McCoy Inc.,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,12,2008,,24,1,2009,Vernissage,9,12,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Charles Pollock [1902-1988] - Stacked Color: Paintings from the 1960s, Jason McCoy Inc., 8.5.2008 - 14.6.2008",Charles Pollock [1902-1988] - Stacked Color,Paintings from the 1960s,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Jason McCoy Inc.,"1,05E+09",,,,,,,,,,,,"Pollock, Charles",137673302,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Jason McCoy Inc.,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,5,2008,,14,6,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"The Essence of Things: Bo Joseph with African Art, Jason McCoy Inc., 13.2.2008 - 8.3.2008",The Essence of Things,Bo Joseph with African Art,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,Plastik,4046277-8,,,,,,,New York,4042011-5,,,,,,,Jason McCoy Inc.,"1,05E+09",,,,,,,,,,,,"Joseph, Bo",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Jason McCoy Inc.,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,2,2008,,8,3,2008,Vernissage,13,2,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,Plastik,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Terrell James - Place for Two Stones, Jason McCoy Inc., 6.9.2007 - 13.10.2007",Terrell James - Place for Two Stones,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,Grafik,4021845-4,Plastik,4046277-8,,,,,New York,4042011-5,,,,,,,Jason McCoy Inc.,"1,05E+09",,,,,,,,,,,,"James, Terrell",1124161791,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Jason McCoy Inc.,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,9,2007,,13,10,2007,Vernissage,14,9,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,Grafik,Plastik,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Martin Kline - Monochrome, Jason McCoy Inc., 23.10.2008 - 29.11.2008",Martin Kline - Monochrome,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Jason McCoy Inc.,"1,05E+09",,,,,,,,,,,,"Kline, Martin",136828841,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Jason McCoy Inc.,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,23,10,2008,,29,11,2008,Vernissage,23,10,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Frank Farmer - Kull Jagah, Jason McCoy Inc., 23.1.2007 - 3.3.2007",Frank Farmer - Kull Jagah,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Jason McCoy Inc.,"1,05E+09",,,,,,,,,,,,"Farmer, Frank",133017281,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Jason McCoy Inc.,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,23,1,2007,,3,3,2007,Vernissage,27,2,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Frederick Kiesler: Endless [1890-1965], Jason McCoy Inc., 15.4.2008 - 3.5.2008",Frederick Kiesler: Endless [1890-1965],,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,Plastik,4046277-8,,,,,,,New York,4042011-5,,,,,,,Jason McCoy Inc.,"1,05E+09",,,,,,,,,,,,"Kiesler, Frederick",118970364,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Jason McCoy Inc.,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,15,4,2008,,3,5,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,Plastik,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Kevin Larmon - Recent Paintings, Jason McCoy Inc., 9.12.2008 - 24.1.2009",Kevin Larmon - Recent Paintings,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Jason McCoy Inc.,"1,05E+09",,,,,,,,,,,,"Larmon, Kevin",1137360445,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Jason McCoy Inc.,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,12,2008,,24,1,2009,Vernissage,9,12,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Kevin Larmon, Jason McCoy Inc., 18.10.2007 - 1.11.2007",Kevin Larmon,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Jason McCoy Inc.,"1,05E+09",,,,,,,,,,,,"Larmon, Kevin",1137360445,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Jason McCoy Inc.,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,18,10,2007,,1,11,2007,Vernissage,25,10,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Masayuki Nagare - Sculpture New to America, Jason McCoy Inc., 23.1.2007 - 3.3.2007",Masayuki Nagare - Sculpture New to America,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Jason McCoy Inc.,"1,05E+09",,,,,,,,,,,,"Nagare, Masayuki",11927812X,Bildhauer:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Jason McCoy Inc.,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,23,1,2007,,3,3,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Catherine Kernan - Listening Water, Jason McCoy Inc., 19.6.2008 - 18.7.2008",Catherine Kernan - Listening Water,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Jason McCoy Inc.,"1,05E+09",,,,,,,,,,,,"Kernan, Catherine",1127562177,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Jason McCoy Inc.,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,19,6,2008,,18,7,2008,Vernissage,26,6,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Charles Pollock - The Chapala Series 1955-1956, Jason McCoy Inc., 8.3.2007 - 21.4.2007",Charles Pollock - The Chapala Series 1955-1956,,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,4021845-4,Malerei,4037220-0,,,,,,,New York,4042011-5,,,,,,,Jason McCoy Inc.,"1,05E+09",,,,,,,,,,,,"Pollock, Charles",137673302,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Jason McCoy Inc.,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,3,2007,,21,4,2007,Vernissage,8,3,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,Malerei,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Andreas Magdanz - Project BND, Janet Borden, Inc., 3.11.2007 - 8.12.2007",Andreas Magdanz - Project BND,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Janet Borden Inc. (New York, N.Y.)",16284078-0,,,,,,,,,,,,"Magdanz, Andreas",11949938X,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Janet Borden, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,11,2007,,8,12,2007,Vernissage,3,11,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Neil Winokur A-Z, Janet Borden, Inc.",Neil Winokur A-Z,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Janet Borden Inc. (New York, N.Y.)",16284078-0,,,,,,,,,,,,"Winokur, Neil",119199378,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Janet Borden, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,2,2007,,,,,Vernissage,1,2,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Hanno Otten - Colorwork, Janet Borden, Inc., 3.6.2004 - 2.7.2004",Hanno Otten - Colorwork,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,"Janet Borden Inc. (New York, N.Y.)",16284078-0,,,,,,,,,,,,"Otten, Hanno",121544613,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Janet Borden, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,6,2004,,2,7,2004,Vernissage,3,6,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Jan Groover, Janet Borden, Inc., 12.1.2008 - 23.2.2008",Jan Groover,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Janet Borden Inc. (New York, N.Y.)",16284078-0,,,,,,,,,,,,"Groover, Jan",11890132X,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Janet Borden, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,12,1,2008,,23,2,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Richard Gordon, Gitterman Gallery, 13.9.2012 - 17.11.2012",Richard Gordon,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Gitterman Gallery,"1,02E+09",,,,,,,,,,,,"Gordon, Richard",17421359X,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gitterman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,9,2012,,17,11,2012,Vernissage,12,9,2012,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Oliver Gagliani, Gitterman Gallery, 7.6.2013 - 9.8.2013",Oliver Gagliani,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Gitterman Gallery,"1,02E+09",,,,,,,,,,,,"Galiani, Oliver",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gitterman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,6,2013,,9,8,2013,Vernissage,6,6,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Josef Breitenbach, Gitterman Gallery, 10.9.2013 - 2.11.2013",Josef Breitenbach,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Gitterman Gallery,"1,02E+09",,,,,,,,,,,,"Breitenbach, Josef",119365359,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gitterman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,9,2013,,2,11,2013,Vernissage,18,9,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Kenneth Josephson, Gitterman Gallery, 11.1.2013 - 16.3.2013",Kenneth Josephson,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Gitterman Gallery,"1,02E+09",,,,,,,,,,,,"Josephson, Kenneth",122033280,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gitterman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,1,2013,,16,3,2013,Vernissage,10,1,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Herbert Matter, Gitterman Gallery, 23.1.2014 - 22.3.2014",Herbert Matter,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Gitterman Gallery,"1,02E+09",,,,,,,,,,,,"Matter, Herbert",119347636,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gitterman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,23,1,2014,,22,3,2014,Vernissage,22,1,2014,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Debbie Fleming Caffery, Gitterman Gallery, 15.12.2006 - 24.2.2007",Debbie Fleming Caffery,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Gitterman Gallery,"1,02E+09",,,,,,,,,,,,"Caffery, Debie Fleming",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gitterman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,15,12,2006,,24,2,2007,Vernissage,14,12,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"William D. Richardson, Gitterman Gallery, 7.3.2007 - 5.5.2007",William D. Richardson,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Gitterman Gallery,"1,02E+09",,,,,,,,,,,,"Richardson, William D.",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gitterman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,3,2007,,5,5,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Allen Frame, Gitterman Gallery, 10.9.2009 - 31.10.2009",Allen Frame,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Gitterman Gallery,"1,02E+09",,,,,,,,,,,,"Frame, Allen",123219396,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gitterman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,9,2009,,31,10,2009,Vernissage,9,9,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Ferenc Berko, Gitterman Gallery, 13.11.2009 - 23.1.2010",Ferenc Berko,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Gitterman Gallery,"1,02E+09",,,,,,,,,,,,"Berko, Ferenc",119073323,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gitterman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,11,2009,,23,1,2010,Vernissage,12,11,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Joshua Lutz, Gitterman Gallery, 11.6.2004 - 7.8.2004",Joshua Lutz,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Gitterman Gallery,"1,02E+09",,,,,,,,,,,,"Lutz, Joshua",174020120,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gitterman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,6,2004,,7,8,2004,Vernissage,10,6,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Roger Catherineau, Gitterman Gallery, 14.12.2007 - 16.2.2008",Roger Catherineau,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Gitterman Gallery,"1,02E+09",,,,,,,,,,,,"Catherineau, Roger",174324472,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gitterman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,12,2007,,16,2,2008,Vernissage,13,12,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Roswell Angier, Gitterman Gallery, 18.5.2007 - 28.7.2007",Roswell Angier,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Gitterman Gallery,"1,02E+09",,,,,,,,,,,,"Angier, Roswell",136352642,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Gitterman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,18,5,2007,,28,7,2007,Vernissage,17,5,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Berlin Noir, Perry Rubenstein Gallery",Berlin Noir,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Perry Rubenstein Gallery (New York, NY)",5570585-6,,,,,,,,,,,,"Ensslin, Felix",13144414X,Kurator:in,,"Boehm, Armin",128629584,Künstler:in,"Hansdóttir, Elín",Künstler:in,"Kroenke, Chris",Künstler:in,"Ottinger, Ulrike",Künstler:in,"Pilz, Christian",Künstler:in,"Reynolds, Ryan",Künstler:in,"Rudolph, Dennis",Künstler:in,"Trenka-Dalton, Sophie-Therese",Künstler:in,"Wutz, Michael",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Perry Rubenstein Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Vernissage,28,11,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Lina Bertucci - Women in the Tattoo Subculture, Perry Rubenstein Gallery",Lina Bertucci - Women in the Tattoo Subculture,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Perry Rubenstein Gallery (New York, NY)",5570585-6,,,,,,,,,,,,"Bertucci, Lina",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Perry Rubenstein Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Vernissage,28,11,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Mike Quinn - Winning is not for Everyone, Perry Rubenstein Gallery, 27.3.2008 - 17.5.2008",Mike Quinn - Winning is not for Everyone,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,Objektkunst,4131740-3,,,,,,,New York,4042011-5,,,,,,,"Perry Rubenstein Gallery (New York, NY)",5570585-6,,,,,,,,,,,,"Quinn, Mike",173469442,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Perry Rubenstein Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,27,3,2008,,17,5,2008,Vernissage,27,3,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,Objektkunst,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Robin Rhode, Perry Rubenstein Gallery, 5.5.2007 - 23.6.2007",Robin Rhode,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Perry Rubenstein Gallery (New York, NY)",5570585-6,,,,,,,,,,,,"Rhode, Robin",130494542,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Perry Rubenstein Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,5,2007,,23,6,2007,Vernissage,5,5,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Mira Nakashima, Perry Rubenstein Gallery, 8.11.2006 - 22.12.2006",Mira Nakashima,,,,,Einzelausstellung,Sonderausstellung,,,,,Design,4011510-0,,,,,,,,,New York,4042011-5,,,,,,,"Perry Rubenstein Gallery (New York, NY)",5570585-6,,,,,,,,,,,,"Nakashima, Mira",188389156,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Perry Rubenstein Gallery,Veranstalter,Cristina Grajales Inc.,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,8,11,2006,,22,12,2006,Vernissage,8,11,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Design,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Adam Pendleton - Bam Split Lab and The Afro Futuristic Underground, Perry Rubenstein Gallery, 2.11.2006 - 22.12.2006",Adam Pendleton - Bam Split Lab and The Afro Futuristic Underground,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,Concept-art,,,,,,,,New York,4042011-5,,,,,,,"Perry Rubenstein Gallery (New York, NY)",5570585-6,,,,,,,,,,,,"Pendleton, Adam",138131708,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Perry Rubenstein Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,2,11,2006,,22,12,2006,Vernissage,2,11,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,Concept-art,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Brock Enright - Good Times Will Never be The Same, Perry Rubenstein Gallery, 20.2.2007 - 31.3.2007",Brock Enright - Good Times Will Never be The Same,,,,,Einzelausstellung,Sonderausstellung,,,,,Medienkunst,4113418-7,,,,,,,,,New York,4042011-5,,,,,,,"Perry Rubenstein Gallery (New York, NY)",5570585-6,,,,,,,,,,,,"Enright, Brock",1063043069,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Perry Rubenstein Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,20,2,2007,,31,3,2007,Vernissage,20,2,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Medienkunst,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Santiago Cucullu - Crikcity & The Walls That Sour Us, Perry Rubenstein Gallery, 10.1.2008 - 16.2.2008",Santiago Cucullu - Crikcity & The Walls That Sour Us,,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,4021845-4,,,,,,,,,New York,4042011-5,,,,,,,"Perry Rubenstein Gallery (New York, NY)",5570585-6,,,,,,,,,,,,"Cucullu, Santiago",174368291,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Perry Rubenstein Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,1,2008,,16,2,2008,Vernissage,10,1,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Successive Approximation: Tauba Auerbach, Daniel Buren, Sol Lewitt, Mike Quinn, Robin Rhode, Perry Rubenstein Gallery, 10.1.2008 - 16.2.2008",Successive Approximation,"Tauba Auerbach, Daniel Buren, Sol Lewitt, Mike Quinn, Robin Rhode",,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,"Perry Rubenstein Gallery (New York, NY)",5570585-6,,,,,,,,,,,,"Auerbach, Tauba",133736717,Maler:in,,"Buren, Daniel",118517570,Maler:in,"Lewitt, Sol",Maler:in,"Quinn, Mike",Maler:in,"Rhode, Robin",Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Perry Rubenstein Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,1,2008,,16,2,2008,Vernissage,10,1,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Dennis Rudolph - The Holy War: Chapter One: The Sacrifice of Youth, Perry Rubenstein Gallery, 12.4.2008 - 17.5.2008",Dennis Rudolph - The Holy War,Chapter One: The Sacrifice of Youth,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,"Perry Rubenstein Gallery (New York, NY)",5570585-6,,,,,,,,,,,,"Rudolph, Dennis",132117134,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Perry Rubenstein Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,12,4,2008,,17,5,2008,Vernissage,12,4,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Håvard Homstvedt - The Close-In, Perry Rubenstein Gallery, 17.10.2008 - 26.11.2008",Håvard Homstvedt - The Close-In,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,"Perry Rubenstein Gallery (New York, NY)",5570585-6,,,,,,,,,,,,"Homstvedt, Havard",,Maler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Perry Rubenstein Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,17,10,2008,,26,11,2008,Vernissage,17,10,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Ry Fyan - I Can Give You What You Want, Perry Rubenstein Gallery, 21.2.2008 - 29.3.2008",Ry Fyan - I Can Give You What You Want,,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,4021845-4,,,,,,,,,New York,4042011-5,,,,,,,"Perry Rubenstein Gallery (New York, NY)",5570585-6,,,,,,,,,,,,"Fyan, Ry",,Grafiker:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Perry Rubenstein Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,21,2,2008,,29,3,2008,Vernissage,21,2,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Diana Al-Hadid, Perry Rubenstein Gallery, 19.10.2007 - 24.11.2007",Diana Al-Hadid,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,"Perry Rubenstein Gallery (New York, NY)",5570585-6,,,,,,,,,,,,"Al-Hadid, Diana",135835518,Bildhauer:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Perry Rubenstein Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,19,10,2007,,24,11,2007,Vernissage,19,10,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Amir Zaki - ?, Perry Rubenstein Gallery, 19.10.2007 - 24.11.2007",Amir Zaki - ?,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,Objektkunst,4131740-3,,,,,,,New York,4042011-5,,,,,,,"Perry Rubenstein Gallery (New York, NY)",5570585-6,,,,,,,,,,,,"Zaki, Amir",1195081979,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Perry Rubenstein Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,19,10,2007,,24,11,2007,Vernissage,19,10,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,Objektkunst,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Jeon Joonho, Perry Rubenstein Gallery, 6.9.2007 - 13.10.2007",Jeon Joonho,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,1228235120,,,,,,,,,New York,4042011-5,,,,,,,"Perry Rubenstein Gallery (New York, NY)",5570585-6,,,,,,,,,,,,"Jeon, Joonho",1029079692,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Perry Rubenstein Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,9,2007,,13,10,2007,Vernissage,6,9,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"David Plowden - Vanishing Point, Laurence Miller Gallery, 3.4.2008 - 31.5.2008",David Plowden - Vanishing Point,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Laurence Miller Gallery (New York, NY)",5547564-4,,,,,,,,,,,,"Plowden, David",119518015,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Laurence Miller Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,4,2008,,31,5,2008,Vernissage,3,4,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Burk Uzzle - Just Add Water: America in Color: Woodstock: Twelve Vintage Photographs, Laurence Miller Gallery, 6.9.2007 - 27.10.2007",Burk Uzzle - Just Add Water: America in Color,Woodstock: Twelve Vintage Photographs,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Laurence Miller Gallery (New York, NY)",5547564-4,,,,,,,,,,,,"Uzzle, Burk",119236346,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Laurence Miller Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,9,2007,,27,10,2007,Vernissage,6,9,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Private Collections III: Highlights From the Estate of Peter Berg, Laurence Miller Gallery, 10.5.2007 - 29.6.2007",Private Collections III: Highlights From the Estate of Peter Berg,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Laurence Miller Gallery (New York, NY)",5547564-4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Laurence Miller Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,5,2007,,29,6,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Julie Mack - on the move, Laurence Miller Gallery, 10.5.2007 - 29.6.2007",Julie Mack - on the move,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Laurence Miller Gallery (New York, NY)",5547564-4,,,,,,,,,,,,"Maeck, Julie",137743394,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Laurence Miller Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,5,2007,,29,6,2007,Vernissage,10,5,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Ray K. Metzker - Singular Sensations, Laurence Miller Gallery, 1.11.2007 - 12.1.2008",Ray K. Metzker - Singular Sensations,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Laurence Miller Gallery (New York, NY)",5547564-4,,,,,,,,,,,,"Metzker, Ray K.",12113251X,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Laurence Miller Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,1,11,2007,,12,1,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Fred Herzog - Vancouver Color, Laurence Miller Gallery, 3.4.2008 - 31.5.2008",Fred Herzog - Vancouver Color,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Laurence Miller Gallery (New York, NY)",5547564-4,,,,,,,,,,,,"Herzog, Fred",133178331,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Laurence Miller Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,4,2008,,31,5,2008,Vernissage,3,4,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Bruce Wrighton - Through an Open Window, Laurence Miller Gallery, 11.9.2008 - 25.10.2008",Bruce Wrighton - Through an Open Window,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Laurence Miller Gallery (New York, NY)",5547564-4,,,,,,,,,,,,"Wrighton, Bruce",1048604454,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Laurence Miller Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,9,2008,,25,10,2008,Vernissage,11,9,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Subjective Photography, Laurence Miller Gallery",Subjective Photography,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Laurence Miller Gallery (New York, NY)",5547564-4,,,,,,,,,,,,"Steinert, Otto",11875324X,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Laurence Miller Gallery,Veranstalter,Erma Staerz / PhotoArt Hamburg,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,,,,,,,,Vernissage,10,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Philippe Halsman - Jump, Laurence Miller Gallery, 1.4.2010 - 28.5.2010",Philippe Halsman - Jump,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Laurence Miller Gallery (New York, NY)",5547564-4,,,,,,,,,,,,"Halsman, Philippe",119032953,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Laurence Miller Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,1,4,2010,,28,5,2010,Vernissage,1,4,2010,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Henrik Olesen, Galerie Buchholz, 24.1.2016 - 5.3.2016",Henrik Olesen,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,1228235120,,,,,,,,,New York,4042011-5,,,,,,,Galerie Daniel Buchholz,5528281-7,,,,,,,,,,,,"Olesen, Henrik",123398975,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Galerie Buchholz,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,24,1,2016,,5,3,2016,Vernissage,24,1,2016,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Mathias Poledna - Substance, Galerie Buchholz, 3.5.2017 - 17.6.2017",Mathias Poledna - Substance,,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,4021845-4,,,,,,,,,New York,4042011-5,,,,,,,Galerie Daniel Buchholz,5528281-7,,,,,,,,,,,,"Poledna, Mathias",121677338,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Galerie Buchholz,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,3,5,2017,,17,6,2017,Vernissage,3,5,2017,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Douglas Crimp - Before Pictures: New York City 1967-1977, Galerie Buchholz, 8.9.2016 - 22.10.2016",Douglas Crimp - Before Pictures,New York City 1967-1977,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,Bildhauer,4139550-5,,,,,,,New York,4042011-5,,,,,,,Galerie Daniel Buchholz,5528281-7,,,,,,,,,,,,"Crimp, Douglas",143593927,Künstler:in,,"Baltrop, Alvin",108305032X,Künstler:in,"Buren, Daniel",Künstler:in,The Cockettes,Künstler:in,"Cornell, Joseph",Künstler:in,"Evans, Walker",Künstler:in,"Goldstein, Jack",Künstler:in,"Hocquenghem, Guy",Künstler:in,"Hujar, Peter",Künstler:in,"James, Charles",Künstler:in,"Jonas, Joan",Künstler:in,"Kelly, Ellsworth",Künstler:in,"Lawler, Louise",Künstler:in,"Leonard, Zoe",Künstler:in,"Levine, Sherrie",Künstler:in,"Longo, Robert",Künstler:in,"Lopez, Antonia",Künstler:in,"Martin, Agnes",Künstler:in,"Matta-Clark, Gordon",Künstler:in,"Owens, Craig",Künstler:in,"Phillips, Esther",Künstler:in,"Rainer, Yvonne",Künstler:in,"Sherman, Cindy",Künstler:in,"Smith, Philip",Künstler:in,"Soukaz, Lionel",Künstler:in,"Tworkov, Jack",Künstler:in,"Vignelli, Massimo",Künstler:in,"Winogrand, Garry",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Galerie Buchholz,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,handschriftlich,,8,9,2016,,22,10,2016,Vernissage,8,9,2016,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,Bildhauer,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Moyra Davey - ""1943"", Galerie Buchholz, 1.3.2018 - 7.4.2018","Moyra Davey - ""1943""",,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Galerie Daniel Buchholz,5528281-7,,,,,,,,,,,,"Davey, Moyra",135664829,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Galerie Buchholz,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,1,3,2018,,7,4,2018,Vernissage,1,3,2018,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Eliza Douglas, Anne Imhof, Galerie Buchholz, 9.9.2017 - 21.10.2017","Eliza Douglas, Anne Imhof",,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Galerie Daniel Buchholz,5528281-7,,,,,,,,,,,,"Douglas, Eliza",1135751498,Künstler:in,,"Imhof, Anne",1043955356,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Galerie Buchholz,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,9,2017,,21,10,2017,Vernissage,9,9,2017,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"In the Belly of the Whale, Tracy Williams, Ltd., 28.6.2007 - 3.8.2007",In the Belly of the Whale,,,,,Gruppenausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,"Tracy Williams Ltd. (New York, NY)",16285245-9,,,,,,,,,,,,"Callery, Patrick",,Kurator:in,,"Bocanegra, Suzanne",1112684158,Künstler:in,"Clisset, Shamus",Künstler:in,"Craycroft, Anna",Künstler:in,"DeBellvue, Lucky",Künstler:in,"Dentz, Shoshana",Künstler:in,"Hegarty, Valerie",Künstler:in,"Kaplan, Laura",Künstler:in,"Krejcarek, Karsten",Künstler:in,"Lazarus, Michael",Künstler:in,"Mendelsohn, Adam",Künstler:in,"Pilson, John",Künstler:in,"Waters, Erin",Künstler:in,"Wiener, Daniel",Künstler:in,"Zivic, Jim",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Tracy Williams, Ltd.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,28,6,2007,,3,8,2007,Vernissage,28,6,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Jennifer Nocon - Elctive Affinities, Tracy Williams, Ltd., 24.2.2007 - 21.4.2007",Jennifer Nocon - Elctive Affinities,,,,,Einzelausstellung,Sonderausstellung,,,Art 38 Basel,16037975-1,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,"Tracy Williams Ltd. (New York, NY)",16285245-9,,,,,,,,,,,,"Nocon, Jennifer",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Tracy Williams, Ltd.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,24,2,2007,,21,4,2007,Vernissage,24,2,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Judy Ledgerwood - Hard Jam, Tracy Williams, Ltd., 11.1.2007 - 20.2.2007",Judy Ledgerwood - Hard Jam,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,"Tracy Williams Ltd. (New York, NY)",16285245-9,,,,,,,,,,,,"Ledgerwood, Judy",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"Tracy Williams, Ltd.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,1,2007,,20,2,2007,Vernissage,11,1,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Georg Herold, Friedrich Petzel Gallery, 8.9. - 21.10.",Georg Herold,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Friedrich Petzel Gallery,6075859-4,,,,,,,,,,,,"Herold, Georg",119240181,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Friedrich Petzel Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,9,,,21,10,,Vernissage,8,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Georg Herold - weekend ü, Friedrich Petzel Gallery, 30.1.2009 - 21.3.2009",Georg Herold - weekend ü,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Friedrich Petzel Gallery,6075859-4,,,,,,,,,,,,"Herold, Georg",119240181,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Friedrich Petzel Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,30,1,2009,,21,3,2009,Vernissage,30,1,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Lynn Chadwick - Retrospectives, Blain|Di Donna, 29.5.2014 - 25.7.2014",Lynn Chadwick - Retrospectives,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,Berlin,4005728-8,London,4074335-4,,,Di Donna,"1,05E+09",Blain|Southern,Blain|Southern,,,,,,,,,,"Chadwick, Lynn",118669028,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Blain|Di Donna,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,29,5,2014,,25,7,2014,,,,,,3,5,2014,,26,7,2014,,,,,,1,5,2014,28,6,2014,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Jean Arp - A Collection of Wood Reliefs and Collages, Blain|Di Donna, 1.11. - 11.12.",Jean Arp - A Collection of Wood Reliefs and Collages,,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,4021845-4,,,,,,,,,New York,4042011-5,,,,,,,Di Donna,"1,05E+09",,,,,,,,,,,,"Arp, Hans",118504398,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Blain|Di Donna,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,1,11,,,11,12,,Vernissage,1,11,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Dan Walsh, Paula Cooper Gallery, 22.2.2008 - 29.3.2008",Dan Walsh,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Paula Cooper Gallery,5169741-5,,,,,,,,,,,,"Walsh, Dan",124044433,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Paula Cooper Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,22,2,2008,,29,3,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Sherrie Levine, Paula Cooper Gallery, 5.4.2008 - 3.5.2008",Sherrie Levine,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Paula Cooper Gallery,5169741-5,,,,,,,,,,,,"Levine, Sherrie",11909553X,Bildhauer:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Paula Cooper Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,4,2008,,3,5,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"John Tremblay, Paula Cooper Gallery, 29.3. - 24.4.",John Tremblay,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Paula Cooper Gallery,5169741-5,,,,,,,,,,,,"Tremblay, John",122126580,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Paula Cooper Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,29,3,,,24,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Robert Wilson - Voom Portraits, Paula Cooper Gallery, 13.1.2007 - 3.2.2007",Robert Wilson - Voom Portraits,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Paula Cooper Gallery,5169741-5,,,,,,,,,,,,"Wilson, Robert",118633503,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Paula Cooper Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,1,2007,,3,2,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +https://www.paulacoopergallery.com/exhibitions/still-life-kicking#tab:slideshow,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Still Life & Kicking, Paula Cooper Gallery, Vogue, 10.5.2007 - 8.6.2007",Still Life & Kicking,,,,,Gruppenausstellung,Sonderausstellung,,,,,Plastik,4046277-8,Malerei,4037220-0,,,,,,,New York,4042011-5,,,,,,,Paula Cooper Gallery,5169741-5,,,,,,,,,,,,"Kazanjian, Dodie",1057103721,Kurator:in,,"Baldessari, John",118506153,Künstler:in,"Cattelan, Maurizio",Künstler:in,"Chamberlain, John",Künstler:in,"Chan, Paul",Künstler:in,"Close, Chuck",Künstler:in,"Condo, George",Künstler:in,"Harrison, Rachel",Künstler:in,"Levine, Sherrie",Künstler:in,"Peyton, Elizabeth",Künstler:in,"Rist, Pipilotti",Künstler:in,"van Bart, Hannah",Künstler:in,"Walsh, Dan",Künstler:in,"Weiner, Lawrence",Künstler:in,"West, Franz",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Paula Cooper Gallery,Veranstalter,Vogue,,,Veranstalter,,,,,,,,,,,,,,,,,,,,,10,5,2007,,8,6,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,Malerei,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"akira KANAYAMA, atsuko TANAKA, Paula Cooper Gallery, 17.1.2008 - 18.2.2008","akira KANAYAMA, atsuko TANAKA",,,,,Gruppenausstellung,Sonderausstellung,,,,,Objektkunst,4131740-3,Installation,1228235120,,,,,,,New York,4042011-5,,,,,,,Paula Cooper Gallery,5169741-5,,,,,,,,,,,,"Kanayama, Akira",121414477,Künstler:in,,"Tanaka, Atsuko",121414442,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Paula Cooper Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,17,1,2008,,18,2,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Objektkunst,Installation,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Hans Haacke, Paula Cooper Gallery, 11.1.2008 - 16.2.2008",Hans Haacke,,,,,Einzelausstellung,Sonderausstellung,,,,,Objektkunst,4032354-7,Installation,1228235120,,,,,,,New York,4042011-5,,,,,,,Paula Cooper Gallery,5169741-5,,,,,,,,,,,,"Haacke, Hans",118699644,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Paula Cooper Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,1,2008,,16,2,2008,Vernissage,11,1,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Objektkunst,Installation,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Meg Webster, Paula Cooper Gallery, 23.2.2008 - 22.3.2008",Meg Webster,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,Installation,1228235120,,,,,,,New York,4042011-5,,,,,,,Paula Cooper Gallery,5169741-5,,,,,,,,,,,,"Webster, Meg",111537074X,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Paula Cooper Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,23,2,2008,,22,3,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,Installation,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Kelley Walker, Paula Cooper Gallery, 31.10.2008 - 13.12.2008",Kelley Walker,,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,4021845-4,,,,,,,,,New York,4042011-5,,,,,,,Paula Cooper Gallery,5169741-5,,,,,,,,,,,,"Walker, Kelley",130048283,Grafiker:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Paula Cooper Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,31,10,2008,,13,12,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Helmut Newton - Private Property: Photographs 1975-1983, Staley-Wise, 30.1.1987 - 29.1.1987",Helmut Newton - Private Property,Photographs 1975-1983,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Staley-Wise Gallery,,,,,,,,,,,,,"Newton, Helmut",118587536,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley-Wise,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,handschriftlich,,30,1,1987,,29,1,1987,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Priscilla Rattazzi - Selected Photographs: 1975-2013, Staley-Wise Gallery, 31.1.2014 - 22.2.2014",Priscilla Rattazzi - Selected Photographs: 1975-2013,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Staley-Wise Gallery,,,,,,,,,,,,,"Rattazzi, Priscilla",124438342,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley-Wise Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,31,1,2014,,22,2,2014,Vernissage,30,1,2014,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Patrick Demarchelier: Part II, Staley-Wise Gallery, 27.9.2013 - 30.11.2013",Patrick Demarchelier: Part II,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Staley-Wise Gallery,,,,,,,,,,,,,"Demarchelier, Patrick",118950452,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley-Wise Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,27,9,2013,,30,11,2013,Vernissage,26,9,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Harry Benson - Work, Staley-Wise Gallery, 14.9.2012 - 27.1.2012",Harry Benson - Work,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Staley-Wise Gallery,,,,,,,,,,,,,"Benson, Harry",123871662,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley-Wise Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,9,2012,,27,1,2012,Vernissage,13,9,2012,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Harry Benson - Get the Picture, Staley-Wise Gallery, 16.12.2017 - 28.1.2017",Harry Benson - Get the Picture,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Staley-Wise Gallery,,,,,,,,,,,,,"Benson, Harry",123871662,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley-Wise Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,16,12,2017,,28,1,2017,Vernissage,15,12,2016,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Jim Marshall and Timothy White - Match Prints, Staley-Wise Gallery, 26.3.2010 - 24.4.2010",Jim Marshall and Timothy White - Match Prints,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Staley-Wise Gallery,,,,,,,,,,,,,"Marshall, Jim",1029782997,Fotograf:in,,"White, Timothy",124424139,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley-Wise Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,26,3,2010,,24,4,2010,Vernissage,25,5,2010,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Mary Ellen Mark - See Behind the Scene, Staley-Wise Gallery, 9.1.2009 - 14.2.2009",Mary Ellen Mark - See Behind the Scene,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Staley-Wise Gallery,,,,,,,,,,,,,"Mark, Mary Ellen",119073609,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley-Wise Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,1,2009,,14,2,2009,Vernissage,8,1,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Patrick Demarchelier: Part I, Staley-Wise Gallery, 12.9.2008 - 25.10.2008",Patrick Demarchelier: Part I,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Staley-Wise Gallery,,,,,,,,,,,,,"Demarchelier, Patrick",118950452,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley-Wise Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,12,9,2008,,25,10,2008,Vernissage,11,9,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Ellen von Unwerth - Fräulein, Staley-Wise Gallery, 11.12.2009 - 30.1.2010",Ellen von Unwerth - Fräulein,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Staley-Wise Gallery,,,,,,,,,,,,,"Unwerth, Ellen von",119322528,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley-Wise Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,12,2009,,30,1,2010,Vernissage,10,12,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Harry Benson, Staley-Wise Gallery, 7.11.2008 - 3.1.2009",Harry Benson,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Staley-Wise Gallery,,,,,,,,,,,,,"Benson, Harry",123871662,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley-Wise Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,11,2008,,3,1,2009,Vernissage,6,11,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"That's Great!: Photographs by Ron Galella, Staley-Wise Gallery, 1.5.2008 - 7.6.2008",That's Great!,Photographs by Ron Galella,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Staley-Wise Gallery,,,,,,,,,,,,,"Galella, Ron",128466634,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley-Wise Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,1,5,2008,,7,6,2008,Vernissage,1,5,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Michael Dweck - Mermaids 2006-2008, Staley-Wise Gallery, 19.6.2008 - 6.9.2008",Michael Dweck - Mermaids 2006-2008,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Staley-Wise Gallery,,,,,,,,,,,,,"Dweck, Michael",130117587,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley-Wise Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,19,6,2008,,6,9,2008,Vernissage,19,6,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Lillian Bassmann - 12 Platinum Prints, Staley-Wise Gallery, 14.2.2008 - 26.4.2008",Lillian Bassmann - 12 Platinum Prints,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Staley-Wise Gallery,,,,,,,,,,,,,"Bassman, Lillian",11948840X,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley-Wise Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,2,2008,,26,4,2008,Vernissage,14,2,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Celebrating 25 Years of Staley-Wise with the 100th Birthday of Horst, Staley-Wise Gallery, 1.12.2006 - 27.1.2007",Celebrating 25 Years of Staley-Wise with the 100th Birthday of Horst,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Staley-Wise Gallery,,,,,,,,,,,,,Horst,118924397,Fotograf:in,,"Warhol, Andy",118629220,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Staley-Wise Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,1,12,2006,,27,1,2007,Vernissage,30,11,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Voom Portraits - Robert Wilson, Phillips de Pury & Company, Paula Cooper, Voom HD Networks, 17.1.2007 - 14.2.2007",Voom Portraits - Robert Wilson,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"Wilson, Robert",118633503,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,Paula Cooper,,,Veranstalter,Voom HD Networks,Veranstalter,,,,,,,,,,,,,,,,,,,17,1,2007,,14,2,2007,Vernissage,16,1,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Lucille Reyboz - Selling Exhibition of Photographs, Phillips de Pury & Company, 10.1.2006 - 26.1.2006",Lucille Reyboz - Selling Exhibition of Photographs,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"Reyboz, Lucille",138324662,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,1,2006,,26,1,2006,Vernissage,9,6,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Daniel Brush - Thirty Years' Work: Selling Exhibition, Phillips de Pury & Company, 31.5.2007 - 30.6.2007",Daniel Brush - Thirty Years' Work,Selling Exhibition,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,Malerei,4037220-0,Objektkunst,4131740-3,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"Brush, Daniel",121062619,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,31,5,2007,,30,6,2007,Vernissage,30,5,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,Malerei,Objektkunst,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Atmospherics - Hani Rashid, Phillips de Pury & Company, 5.6.2008 - 28.6.2008",Atmospherics - Hani Rashid,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"Rashid, Hani",12386531X,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,6,2008,,28,6,2008,Vernissage,12,6,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"McCallum & Tarry - Endurance, Marvelli Gallery, 14.10.2004 - 20.11.2004",McCallum & Tarry - Endurance,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Marvelli Gallery,,,,,,,,,,,,,"McCallum, Bradley",1209156776,Künstler:in,,"Tarry, Jacqueline",1209156180,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Marvelli Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,10,2004,,20,11,2004,Vernissage,14,10,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"John Houshmand - Extensions and Intensions, Hous Projects, 9.10.2008 - 13.12.2008",John Houshmand - Extensions and Intensions,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,1228235120,Plastik,4046277-8,,,,,,,New York,4042011-5,,,,,,,Hous Projects,,,,,,,,,,,,,"Houshmand, John",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hous Projects,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,10,2008,,13,12,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Installation,Plastik,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Pre-Colombian Textile Art, Paul Kasmin Gallery, 15.5.1996 - 15.6.1996",Pre-Colombian Textile Art,,,,,Gruppenausstellung,Sonderausstellung,,,,,Textilkunst,4059624-2,,,,,,,,,New York,4042011-5,,,,,,,Paul Kasmin Gallery,10024679-5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Paul Kasmin Gallery,Veranstalter,"Paul Hughes Fine Textile Art, London",,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,15,5,1996,,15,6,1996,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Textilkunst,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"The Space Beyond, Camera Club of New York (CCNY), 9.1.2014 - 15.2.2014",The Space Beyond,,1074534271,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,The Camera Club of New York,"1,07E+09",,,,,,,,,,,,"Bosse, Katharina",123063779,Kurator:in,,"Eilers, Norbert",121221224X,Künstler:in,"Grützner, Andrea",Künstler:in,"Schlotter, Robert",Künstler:in,"Winkler, Paula",Künstler:in,"Gehring, AlexanderKünstler:in",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Camera Club of New York (CCNY),Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,1,2014,,15,2,2014,Vernissage,9,1,2014,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],Beteiligte Person 12,From Above,,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,4037220-0,Fotografie,4045895-7,Plastik,4046277-8,Installation,1228235120,Grafik,4021845-4,New York,4042011-5,,,,,,,Di Donna,"1,05E+09",,,,,,,,,,,,"Church, Leslie Frederic",135585511,Künstler:in,,"Delaunay, Robert",118524496,Künstler:in,"Diebenkorn, Richard",Künstler:in,"Duchamp, Marcel",Künstler:in,"Hopper, Edward",Künstler:in,"Klein, Yves",Künstler:in,"Loeb, Damian",Künstler:in,"Longo, Robert",Künstler:in,"Magritte, René",Künstler:in,"Ray, Man",Künstler:in,"McEwen, Adam",Künstler:in,"Noland, Kenneth",Künstler:in,"Richter, Gerhard",Künstler:in,"Ruscha, Ed",Künstler:in,"Sodi, Bosco",Künstler:in,"Thiebaud, Wayne",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Di Donna,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,23,4,2015,,29,5,2015,Vernissage,23,4,2015,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,Fotografie,Plastik,Installation,Grafik,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Adam Fuss - Details of Love, Robert Miller",Adam Fuss - Details of Love,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Robert Miller Gallery (New York, NY)",3006161-1,,,,,,,,,,,,"Fuss, Adam",119413604,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Robert Miller,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Vernissage,2,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Joan Snyder, Jessica Stockholder, Jay Gorney Modern Art, 8.1.1994 - 12.2.1994","Joan Snyder, Jessica Stockholder",,,,,Gruppenausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Jay Gorney Modern Art,"1,27E+09",,,,,,,,,,,,"Snyder, Joan",11938129X,Künstler:in,,"Stockholder, Jessica",119246112,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Jay Gorney Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,1,1994,,12,2,1994,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Artists & Amateurs: Photographs & Photobooks, Swann Auction Galleries, 13.10. - 18.10.",Artists & Amateurs: Photographs & Photobooks,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Swann Galleries,3005918-5,,,,,,,,,,,,"Siskind, Aaron",120772833,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Swann Auction Galleries,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,10,,,18,10,,Auktion,18,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"The Knowing Eye: Photographs & Photobooks, Swann Auction Galleries, 14.4. - 19.4.",The Knowing Eye: Photographs & Photobooks,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Swann Galleries,3005918-5,,,,,,,,,,,,"Henri, Florence",119004674,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Swann Auction Galleries,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,4,,,19,4,,Auktion,19,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Photographic Literature & Photographs, Swann Auction Galleries, 8.12. - 12.12.",Photographic Literature & Photographs,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Swann Galleries,3005918-5,,,,,,,,,,,,"Struss, Karl",119296454,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Swann Auction Galleries,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,12,,,12,12,,Auktion,13,12,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Contemporary Art - Under the Influence: Associates in New York, Phillips de Pury & Company, 25.3.2008 - 19.4.2008",Contemporary Art - Under the Influence,Associates in New York,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Phillips de Pury & Company,,,,,,,,,,,,,"Hirst, Damien",119210738,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Phillips de Pury & Company,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,25,3,2008,,19,4,2008,Auktion,31,3,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Jeff Wall, Marian Goodman Gallery, 20.9.2002 - 2.11.2002",Jeff Wall,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,Installation,,,,,,,,New York,4042011-5,,,,,,,Marian Goodman Gallery,,,,,,,,,,,,,"Wall, Jeff",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Marian Goodman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,20,9,2002,,2,11,2002,Vernissage,20,9,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Maurizio Cattelan, Marian Goodman Gallery, 30.4.2002 - 15.6.2002",Maurizio Cattelan,,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,Installation,,,,,,,,New York,4042011-5,,,,,,,Marian Goodman Gallery,,,,,,,,,,,,,"Cattelan, Maurizio",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Marian Goodman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,30,4,2002,,15,6,2002,Vernissage,30,4,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Steve McQueen - Films, Marian Goodman Gallery, 22.5.1997 - 28.4.1997",Steve McQueen - Films,,,,,Einzelausstellung,Sonderausstellung,,,,,Medienkunst,,Installation,,,,,,,,New York,4042011-5,,,,,,,Marian Goodman Gallery,,,,,,,,,,,,,"McQueen, Steve",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Marian Goodman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,22,5,1997,,28,4,1997,Vernissage,22,5,1997,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Jeff Wall, Marian Goodman Gallery, 15.4. - 16.5.",Jeff Wall,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,Installation,,,,,,,,New York,4042011-5,,,,,,,Marian Goodman Gallery,,,,,,,,,,,,,"Wall, Jeff",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Marian Goodman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,15,4,,,16,5,,Vernissage,15,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Jacqueline Donachie - Home Taping, 1996, Marian Goodman Gallery, 4.6.1996 - 12.7.1996","Jacqueline Donachie - Home Taping, 1996",,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,,Medienkunst,,,,,,,,New York,4042011-5,,,,,,,Marian Goodman Gallery,,,,,,,,,,,,,Jacqueline Donachie,,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Marian Goodman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,4,6,1996,,12,7,1996,Vernissage,4,6,1996,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Thomas Struth - New Photographs, Marian Goodman Gallery, 22.5.1997 - 28.4.1997",Thomas Struth - New Photographs,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Marian Goodman Gallery,,,,,,,,,,,,,"Struth, Thomas",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Marian Goodman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,22,5,1997,,28,4,1997,Vernissage,22,5,1997,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Joseph Bartscherer, Marian Goodman Gallery, 7.9.1995 - 30.9.1995",Joseph Bartscherer,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Marian Goodman Gallery,,,,,,,,,,,,,"Bartscherer, Joseph",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Marian Goodman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,9,1995,,30,9,1995,Vernissage,12,9,1995,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"The Section Publicité of the Musée D'Art Moderne - Départment des Aigles, Marian Goodman Gallery, 6.10.1995 - 25.11.1995",The Section Publicité of the Musée D'Art Moderne - Départment des Aigles,,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,Grafik,,Installation,,,,,,New York,4042011-5,,,,,,,Marian Goodman Gallery,,,,,,,,,,,,,"Broodthaers, Marcel",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Marian Goodman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,10,1995,,25,11,1995,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Tony Cragg, Marian Goodman Gallery, 20.3.1998 - 25.4.1998",Tony Cragg,,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,,,,,,,,,New York,4042011-5,,,,,,,Marian Goodman Gallery,,,,,,,,,,,,,"Cragg, Tony",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Marian Goodman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,20,3,1998,,25,4,1998,Vernissage,20,3,1998,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Jeff Wall, Marian Goodman Gallery, 30.1.1998 - 14.3.1998",Jeff Wall,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Marian Goodman Gallery,,,,,,,,,,,,,"Wall, Jeff",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Marian Goodman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,30,1,1998,,14,3,1998,Vernissage,30,1,1998,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Thomas Schütte, Marian Goodman Gallery, 8.3.1996 - 20.4.1996",Thomas Schütte,,,,,Einzelausstellung,Sonderausstellung,,,,,Bildhauerei,,Grafik,,,,,,,,New York,4042011-5,,,,,,,Marian Goodman Gallery,,,,,,,,,,,,,"Schütte, Thomas",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Marian Goodman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,3,1996,,20,4,1996,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Gabriel Orozco, Marian Goodman Gallery, 12.9. - 15.10.",Gabriel Orozco,,,,,Einzelausstellung,Sonderausstellung,,,,,Konzeptkunst,,,,,,,,,,New York,4042011-5,,,,,,,Marian Goodman Gallery,,,,,,,,,,,,,"Orozco, Gabriel",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Marian Goodman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,12,9,,,15,10,,Vernissage,16,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Joseph Bartscherer - Nevada, Marian Goodman Gallery, 12.9.1997 - 1.11.1997",Joseph Bartscherer - Nevada,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Marian Goodman Gallery,,,,,,,,,,,,,"Bartscherer, Joseph",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Marian Goodman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,12,9,1997,,1,11,1997,Vernissage,12,9,1997,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Marcel Broodthaers, Marian Goodman Gallery, 12.9. - 1.11.",Marcel Broodthaers,,,,,Einzelausstellung,Sonderausstellung,,,20th anniversary,,Bildhauerei,,Grafik,,Installation,,,,,,New York,4042011-5,,,,,,,Marian Goodman Gallery,,,,,,,,,,,,,"Broothaers, Marcel",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Marian Goodman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,12,9,,,1,11,,,12,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"A Summer Show, Marian Goodman Gallery",A Summer Show,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,Bildhauerei,,Installation,,,,,,New York,4042011-5,,,,,,,Marian Goodman Gallery,,,,,,,,,,,,,"Artschwager, Richard",,Künstler:in,,"Baumgarten, Lothar",,Künstler:in,"Cattelan, Maurizio",Künstler:in,"Casebere, James",Künstler:in,"Deacon, Richard",Künstler:in,"Horn, Rebecca",Künstler:in,"Munoz, Juan",Künstler:in,"Orozco, Gabriel",Künstler:in,"Penone, Giuseppe",Künstler:in,"Richter, Gerhard",Künstler:in,"Struth, Thomas",Künstler:in,"Toroni, Niele",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Marian Goodman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,7,1997,,,8,1997,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Dan Graham - Models To Projects 1978-1995, Marian Goodman Gallery, 18.1.1996 - 2.3.1996",Dan Graham - Models To Projects 1978-1995,,,,,Einzelausstellung,Sonderausstellung,,,,,Design,,Bildhauerei,,,,,,,,New York,4042011-5,,,,,,,Marian Goodman Gallery,,,,,,,,,,,,,"Graham, Dan",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Marian Goodman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,18,1,1996,,2,3,1996,Vernissage,18,1,1996,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Christian Boltanski, Marian Goodman Gallery, 10.2.1995 - 11.3.1995",Christian Boltanski,,,,,Einzelausstellung,Sonderausstellung,,,,,Installation,,,,,,,,,,New York,4042011-5,,,,,,,Marian Goodman Gallery,,,,,,,,,,,,,"Boltanski, Christian",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Marian Goodman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,2,1995,,11,3,1995,Vernissage,10,2,1995,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Jeff Wall, Marian Goodman Gallery, 28.4.1995 - 10.6.1995",Jeff Wall,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Marian Goodman Gallery,,,,,,,,,,,,,"Wall, Jeff",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Marian Goodman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,28,4,1995,,10,6,1995,Vernissage,28,4,1995,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Thomas Struth, Marian Goodman Gallery, 30.4.2002 - 15.6.2002",Thomas Struth,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,Marian Goodman Gallery,,,,,,,,,,,,,"Struth, Thomas",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Marian Goodman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,30,4,2002,,15,6,2002,Vernissage,30,4,2002,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Gerhard Richter - Paintings 1996-2001, Marian Goodman Gallery, 14.9.2001 - 27.10.2001",Gerhard Richter - Paintings 1996-2001,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,Marian Goodman Gallery,,,,,,,,,,,,,"Richter, Gerhard",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Marian Goodman Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,9,2001,,27,10,2001,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"George Tice - Stone Walls, Grey Skies, A Vision of Yorkshire, The Witkin Gallery, Inc., 14.4.1992 - 23.5.1992","George Tice - Stone Walls, Grey Skies, A Vision of Yorkshire",,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Witkin Gallery, Inc.",,,,,,,,,,,,,"Tice, George",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"The Witkin Gallery, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,4,1992,,23,5,1992,Vernissage,14,4,1992,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Carl Chiarenza - Four Decades, The Witkin Gallery, Inc., 29.5.1996 - 12.7.1996",Carl Chiarenza - Four Decades,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Witkin Gallery, Inc.",,,,,,,,,,,,,"Chiarenza, Carl",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"The Witkin Gallery, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,29,5,1996,,12,7,1996,Vernissage,5,6,1996,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"The Japanese Tattoo - Sandi Fellman, The Witkin Gallery, Inc., 13.1. - 21.2.",The Japanese Tattoo - Sandi Fellman,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,Grafik,,,,,,,,New York,4042011-5,,,,,,,"The Witkin Gallery, Inc.",,,,,,,,,,,,,"Fellman, Sandi",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"The Witkin Gallery, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,1,,,21,2,,Vernissage,13,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Leonard Sussman - Photographs of Tuscany and Umbria, The Witkin Gallery, Inc., 2.12.1986 - 10.1.1987",Leonard Sussman - Photographs of Tuscany and Umbria,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Witkin Gallery, Inc.",,,,,,,,,,,,,"Sussman, Leonard",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"The Witkin Gallery, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,2,12,1986,,10,1,1987,Vernissage,2,12,1986,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Wendell MacRAE - Vintage Photographs of New York in the 30s, The Witkin Gallery, Inc., 15.7.1986 - 22.8.1986",Wendell MacRAE - Vintage Photographs of New York in the 30s,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Witkin Gallery, Inc.",,,,,,,,,,,,,"MacRAE, Wendell",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"The Witkin Gallery, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,15,7,1986,,22,8,1986,Vernissage,16,7,1986,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Beatrice Helg - Photographs, The Witkin Gallery, Inc., 28.1.1986 - 1.3.1986",Beatrice Helg - Photographs,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Witkin Gallery, Inc.",,,,,,,,,,,,,"Helg, Beatrice",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"The Witkin Gallery, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,28,1,1986,,1,3,1986,Vernissage,28,1,1986,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Mario Post Wolcott - Photographs from the FSA, The Witkin Gallery, Inc., 29.5.1984 - 30.6.1984",Mario Post Wolcott - Photographs from the FSA,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Witkin Gallery, Inc.",,,,,,,,,,,,,"Wolcott, Marion Post",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"The Witkin Gallery, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,29,5,1984,,30,6,1984,Vernissage,29,5,1984,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Christopher James - New Paintings: Swimmer Series: Photographs: Winter Pool Series, The Witkin Gallery, Inc., 18.10.1983 - 26.11.1983",Christopher James - New Paintings: Swimmer Series,Photographs: Winter Pool Series,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,Fotografie,,,,,,,,New York,4042011-5,,,,,,,"The Witkin Gallery, Inc.",,,,,,,,,,,,,"James, Christopher",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"The Witkin Gallery, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,18,10,1983,,26,11,1983,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Brett Weston - A Selection From Portfolios, The Witkin Gallery, Inc., 29.3.1995 - 13.5.1995",Brett Weston - A Selection From Portfolios,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Witkin Gallery, Inc.",,,,,,,,,,,,,"Weston, Brett",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"The Witkin Gallery, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,29,3,1995,,13,5,1995,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Beatrice Helg - Recent Cibachrome and Polaroid Photographs, The Witkin Gallery, Inc., 23.5.1989 - 8.7.1989",Beatrice Helg - Recent Cibachrome and Polaroid Photographs,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Witkin Gallery, Inc.",,,,,,,,,,,,,"Helg, Beatrice",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"The Witkin Gallery, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,23,5,1989,,8,7,1989,Vernissage,23,5,1989,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"George A. Tice - Lincoln: Photographs on the occasion of Lincoln's 175th birthday, The Witkin Gallery, Inc., 29.2.1984 - 7.4.1984",George A. Tice - Lincoln,Photographs on the occasion of Lincoln's 175th birthday,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Witkin Gallery, Inc.",,,,,,,,,,,,,"Tice, George A.",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"The Witkin Gallery, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,29,2,1984,,7,4,1984,Vernissage,28,2,1984,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Jerry N. Uelsmann - Museum Studies, The Witkin Gallery, Inc., 1.11.1995 - 9.12.1995",Jerry N. Uelsmann - Museum Studies,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Witkin Gallery, Inc.",,,,,,,,,,,,,"Uelsmann, Jerry N.",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"The Witkin Gallery, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,1,11,1995,,9,12,1995,Vernissage,4,11,1995,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Doris Ulman - Vintage Platinum Photographs, The Witkin Gallery, Inc., 8.1.1985 - 9.2.1985",Doris Ulman - Vintage Platinum Photographs,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Witkin Gallery, Inc.",,,,,,,,,,,,,"Ulmann, Doris",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"The Witkin Gallery, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,1,1985,,9,2,1985,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Michael Johnson - Recent Work, The Witkin Gallery, Inc., 24.1.1996 - 2.3.1996",Michael Johnson - Recent Work,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,"The Witkin Gallery, Inc.",,,,,,,,,,,,,"Johnson, Michael",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"The Witkin Gallery, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,24,1,1996,,2,3,1996,Vernissage,17,2,1996,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Fay Godwin - Photographs, The Witkin Gallery, Inc., 31.5.1987 - 2.5.1987",Fay Godwin - Photographs,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Witkin Gallery, Inc.",,,,,,,,,,,,,"Godwin, Fay",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"The Witkin Gallery, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,31,5,1987,,2,5,1987,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Bruce Cratsley - Photographs, The Witkin Gallery, Inc., 31.3.1987 - 2.5.1987",Bruce Cratsley - Photographs,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Witkin Gallery, Inc.",,,,,,,,,,,,,"Cratsley, Bruce",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"The Witkin Gallery, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,31,3,1987,,2,5,1987,Vernissage,31,3,1987,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Leigh Wiener - Portraits, The Witkin Gallery, Inc., 8.9.1987 - 17.10.1987",Leigh Wiener - Portraits,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Witkin Gallery, Inc.",,,,,,,,,,,,,"Wiener, Leigh",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"The Witkin Gallery, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,9,1987,,17,10,1987,Vernissage,12,9,1987,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Michael Eastman - Photographs, The Witkin Gallery, Inc., 9.6.1987 - 11.7.1987",Michael Eastman - Photographs,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Witkin Gallery, Inc.",,,,,,,,,,,,,"Eastman, Michael",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"The Witkin Gallery, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,6,1987,,11,7,1987,Vernissage,13,6,1987,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Janine Niepce, The Witkin Gallery, Inc., 13.9.1994 - 22.10.1994",Janine Niepce,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Witkin Gallery, Inc.",,,,,,,,,,,,,"Niepce, Janine",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"The Witkin Gallery, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,9,1994,,22,10,1994,Vernissage,17,9,1994,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Gary Tepper - The American West & Siberian Landscape, The Witkin Gallery, Inc., 8.12.1993 - 15.1.1994",Gary Tepper - The American West & Siberian Landscape,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Witkin Gallery, Inc.",,,,,,,,,,,,,"Tepfer, Gary",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"The Witkin Gallery, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,12,1993,,15,1,1994,Vernissage,11,12,1994,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Gracila Iturbide, The Witkin Gallery, Inc., 26.10.1993 - 4.12.1993",Gracila Iturbide,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Witkin Gallery, Inc.",,,,,,,,,,,,,"Iturbide, Graciela",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"The Witkin Gallery, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,26,10,1993,,4,12,1993,Vernissage,30,10,1993,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Margaretta K. Mitchell, The Witkin Gallery, Inc., 17.4.1996 - 25.5.1996",Margaretta K. Mitchell,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Witkin Gallery, Inc.",,,,,,,,,,,,,"Mitchell, Margaretta K.",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"The Witkin Gallery, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,17,4,1996,,25,5,1996,Vernissage,20,4,1996,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Susanna Briselli, The Witkin Gallery, Inc., 17.4.1996 - 25.5.1996",Susanna Briselli,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,Malerei,,,,,,,,New York,4042011-5,,,,,,,"The Witkin Gallery, Inc.",,,,,,,,,,,,,"Briselli, Susanna",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"The Witkin Gallery, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,17,4,1996,,25,5,1996,Vernissage,20,4,196,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Sandi Fellman - Recent Work, The Witkin Gallery, Inc., 25.6.1985 - 23.8.1985",Sandi Fellman - Recent Work,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Witkin Gallery, Inc.",,,,,,,,,,,,,"Fellman, Sandi",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"The Witkin Gallery, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,25,6,1985,,23,8,1985,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Willy Ronis, The Witkin Gallery, Inc., 19.9.1995 - 28.10.1995",Willy Ronis,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Witkin Gallery, Inc.",,,,,,,,,,,,,"Ronis, Willy",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"The Witkin Gallery, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,19,9,1995,,28,10,1995,Vernissage,23,9,1995,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Mario Cravo Neto, The Witkin Gallery, Inc., 25.10.1994 - 3.12.1994",Mario Cravo Neto,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Witkin Gallery, Inc.",,,,,,,,,,,,,"Neto, Mario Cravo",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"The Witkin Gallery, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,25,10,1994,,3,12,1994,Vernissage,29,10,1994,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Koichiro Kurita, The Witkin Gallery, Inc., 6.12.1994 - 28.1.1995",Koichiro Kurita,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Witkin Gallery, Inc.",,,,,,,,,,,,,"Kurita, Koichiro",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"The Witkin Gallery, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,12,1994,,28,1,1995,Vernissage,10,12,1995,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Carl Chiarenza - Four Decades, The Witkin Gallery, Inc., 29.5.1996 - 12.7.1996",Carl Chiarenza - Four Decades,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Witkin Gallery, Inc.",,,,,,,,,,,,,"Chiarenza, Carl",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"The Witkin Gallery, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,29,5,1996,,12,7,1996,Vernissage,5,6,1996,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Stephan Brigidi - Carnevale di Venezia, 1995, The Witkin Gallery, Inc., 29.5.1996 - 12.7.1996","Stephan Brigidi - Carnevale di Venezia, 1995",,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Witkin Gallery, Inc.",,,,,,,,,,,,,"Brigidi, Stephan",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"The Witkin Gallery, Inc.",Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,29,5,1996,,12,7,1996,Vernissage,5,6,1996,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Danny Lyon - Photographs 1962-1987, PaceWildensteinMacGill, 5.5.1987 - 6.6.1987",Danny Lyon - Photographs 1962-1987,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"The Witkin Gallery, Inc.",,,,,,,,,,,,,"Lyon, Danny",,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,PaceWildensteinMacGill,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,5,5,1987,,6,6,1987,Vernissage,6,5,1987,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Harry Callahan - Theme and Variation, PaceWildensteinMacGill, 29.2.1996 - 6.4.1996",Harry Callahan - Theme and Variation,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,Grafik,,Bildhauerei,,,,,,New York,4042011-5,,,,,,,PaceWildensteinMacGill,,,,,,,,,,,,,"Callahan, Harry",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,PaceWildensteinMacGill,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,29,2,1996,,6,4,1996,Vernissage,5,3,1996,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"William Christenberry - Drawings, Photographs, Sculptures, PaceWildensteinMacGill, 12.1.1995 - 11.2.1995","William Christenberry - Drawings, Photographs, Sculptures",,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,PaceWildensteinMacGill,,,,,,,,,,,,,"Christenberry, William",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,PaceWildensteinMacGill,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,12,1,1995,,11,2,1995,Vernissage,12,1,1995,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Robert Frank - Flower Is...: Paris, 1949-1951, PaceWildensteinMacGill, 16.1.1997 - 22.2.1997",Robert Frank - Flower Is...,"Paris, 1949-1951",,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,PaceWildensteinMacGill,,,,,,,,,,,,,"Frank, Robert",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,PaceWildensteinMacGill,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,16,1,1997,,22,2,1997,Vernissage,16,1,1997,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Joel Sternfeld - New Portraits, PaceWildensteinMacGill, 16.1.1997 - 22.2.1997",Joel Sternfeld - New Portraits,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,PaceWildensteinMacGill,,,,,,,,,,,,,"Sternfeld, Joel",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,PaceWildensteinMacGill,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,16,1,1997,,22,2,1997,Vernissage,16,1,1997,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Emmet Gowin, PaceWildensteinMacGill, 16.5.1996 - 29.6.1996",Emmet Gowin,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,PaceWildensteinMacGill,,,,,,,,,,,,,"Gowin, Emmet",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,PaceWildensteinMacGill,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,16,5,1996,,29,6,1996,Vernissage,16,5,1996,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Diana Michener - Corpus, PaceWildensteinMacGill, 16.5.1996 - 29.6.1996",Diana Michener - Corpus,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,PaceWildensteinMacGill,,,,,,,,,,,,,"Michener, Diana",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,PaceWildensteinMacGill,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,16,5,1996,,29,6,1996,Vernissage,16,5,1996,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Jenny Saville & Glen Luchford - Bing Wright, PaceWildensteinMacGill, 11.7.1996 - 29.8.1996",Jenny Saville & Glen Luchford - Bing Wright,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,PaceWildensteinMacGill,,,,,,,,,,,,,"Saville, Jenny",,Künstler:in,,"Luchford, Glen",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,PaceWildensteinMacGill,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,7,1996,,29,8,1996,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Irving Penn - Fringes, PaceWildensteinMacGill, 11.4.1996 - 11.5.1996",Irving Penn - Fringes,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,PaceWildensteinMacGill,,,,,,,,,,,,,"Penn, Irving",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,PaceWildensteinMacGill,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,11,4,1996,,11,5,1996,Vernissage,11,4,1996,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Louisa Chase, Robert Miller Gallery, 27.3.1984 - 21.4.1984",Louisa Chase,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"Robert Miller Gallery (New York, NY)",,,,,,,,,,,,,"Chase, Louisa",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Robert Miller Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,27,3,1984,,21,4,1984,Vernissage,27,3,1984,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Louise Bourgeois - Paintings from the 1940s, Robert Miller Gallery, 6.1.1987 - ..",Louise Bourgeois - Paintings from the 1940s,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"Robert Miller Gallery (New York, NY)",,,,,,,,,,,,,"Bourgeois, Louise",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Robert Miller Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,6,1,1987,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Raoul Ubac - Photographs of the 30's and 40's, Robert Miller Gallery, 4.11.1986 - 29.11.1986",Raoul Ubac - Photographs of the 30's and 40's,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"Robert Miller Gallery (New York, NY)",,,,,,,,,,,,,"Ubac, Raoul",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Robert Miller Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,4,11,1986,,29,11,1986,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Joan Snyder, Robert Miller Gallery, 26.4.2001 - 26.5.2001",Joan Snyder,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,,,,,,,,,,New York,4042011-5,,,,,,,"Robert Miller Gallery (New York, NY)",,,,,,,,,,,,,"Snyder, Joan",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Robert Miller Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,26,4,2001,,26,5,2001,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Milton Resnick - X Space, Robert Miller Gallery, 14.2.2001 - 17.3.2001",Milton Resnick - X Space,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,"Robert Miller Gallery (New York, NY)",,,,,,,,,,,,,"Resnick, Milton",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Robert Miller Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,14,2,2001,,17,3,2001,Vernissage,14,2,2001,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Armando Morales, Robert Miller Gallery, 19.11.2004 - 8.1.2005",Armando Morales,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,,,,,,,,,,New York,4042011-5,,,,,,,"Robert Miller Gallery (New York, NY)",,,,,,,,,,,,,"Morales, Armando",,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Robert Miller Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,19,11,2004,,8,1,2005,Vernissage,19,11,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],"Rubber, Robert Miller Gallery, 27.1.1998 - 28.2.1998",Rubber,,,,,Gruppenausstellung,Sonderausstellung,,,,,Bildhauerei,,Installation,,,,,,,,New York,4042011-5,,,,,,,"Robert Miller Gallery (New York, NY)",,,,,,,,,,,,,"Booker, Chakaia",,Künstler:in,,"Bourgeois, Louise",,Künstler:in,"Hesse, Eva",Künstler:in,"McGill, Melissa",Künstler:in,"Nauman, Bruce",Künstler:in,"Overby, Robert",Künstler:in,"Serra, Richard",Künstler:in,"Silverthorne, Jeanne",Künstler:in,"Whiteread, Rachel",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Robert Miller Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,27,1,1998,,28,2,1998,Vernissage,27,1,1998,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],", Robert Miller Gallery",,,,,,,,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,"Robert Miller Gallery (New York, NY)",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Robert Miller Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],", Robert Miller Gallery",,,,,,,,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,"Robert Miller Gallery (New York, NY)",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Robert Miller Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],", Robert Miller Gallery",,,,,,,,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,"Robert Miller Gallery (New York, NY)",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Robert Miller Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],", Robert Miller Gallery",,,,,,,,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,"Robert Miller Gallery (New York, NY)",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Robert Miller Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],", Robert Miller Gallery",,,,,,,,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,"Robert Miller Gallery (New York, NY)",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Robert Miller Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],", Robert Miller Gallery",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Robert Miller Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],", Robert Miller Gallery",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Robert Miller Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],", Robert Miller Gallery",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Robert Miller Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],", ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],", ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],", ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],", ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],", ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],", ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],", ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],", ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],", ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],", ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],", ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Galerien],", ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],"Nancy Rubins - Mattresses & Cakes 1993, Paul Kasmin Gallery, 26.3.1993 - 24.4.1993",Nancy Rubins - Mattresses & Cakes 1993,,,,,Einzelausstellung,Sonderausstellung,,,,,Plastik,4046277-8,,,,,,,,,New York,4042011-5,,,,,,,Howard Greenberg Gallery,10024679-5,,,,,,,,,,,,"Rubins, Nancy",120568004,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Paul Kasmin Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,26,3,1993,,24,4,1993,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Plastik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],"Morris Sato - Lightshowers: with video images by Paul Ryan, Lucas Schoormans Gallery, 25.1.2007 - 24.2.2007",Morris Sato - Lightshowers,with video images by Paul Ryan,,,,Einzelausstellung,Sonderausstellung,,,,,Design,4011510-0,Medienkunst,,,,,,,,New York,4042011-5,,,,,,,"Lucas Schoormans Gallery (New York, NY)",10344862-7,,,,,,,,,,,,"Sato, Morris",,Künstler:in,,"Ryan, Paul",137592515,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Lucas Schoormans Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,25,1,2007,,24,2,2007,Vernissage,25,1,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Design,Medienkunst,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],"Michael Smith - Drawings and Videos (from storage), Christine Burgin, 13.4.2007 - 12.5.2007",Michael Smith - Drawings and Videos (from storage),,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,4021845-4,Medienkunst,,,,,,,,New York,4042011-5,,,,,,,Christine Burgin Gallery,5113966-2,,,,,,,,,,,,"Smith, Michael",123071720,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Christine Burgin,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,13,4,2007,,12,5,2007,Vernissage,13,4,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,Medienkunst,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],"Juergen Teller - Ukraine, Lehmann Maupin, 7.2.2008 - 15.3.2008",Juergen Teller - Ukraine,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Lehmann Maupin Gallery,"1,04E+09",,,,,,,,,,,,"Teller, Juergen",119424355,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Lehmann Maupin,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,2,2008,,15,3,2008,Vernissage,7,2,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],"Jean Royère, Sonnabend Gallery, 8.3.2008 - 12.4.2008",Jean Royère,,,,,Einzelausstellung,Sonderausstellung,,,,,Design,4011510-0,,,,,,,,,New York,4042011-5,,,,,,,Sonnabend Gallery,5198938-4,,,,,,,,,,,,"Royère, Jean",121806073,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Sonnabend Gallery,Veranstalter,Galerie Patrick Seguin,,,Kurator:in,Galerie Jaques Lacoste,Kurator:in,,,,,,,,,,,,,,,,,,,8,3,2008,,12,4,2008,Vernissage,8,3,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Design,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],"Ai Weiwei, Robert Miller Gallery, 9.9.2004 - 9.10.2004",Ai Weiwei,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,Objektkunst,4131740-3,,,,,,,New York,4042011-5,,,,,,,"Robert Miller Gallery (New York, NY)",3006161-1,,,,,,,,,,,,"Ai, Weiwei",129428205,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Robert Miller Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,9,9,2004,,9,10,2004,Vernissage,9,9,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,Objektkunst,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],"Sigrid Rothe - ""Psychic Garden"", Lobby Gallery, Conde Nast, 1.5.2008 - 12.6.2008","Sigrid Rothe - ""Psychic Garden""",,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Lobby Gallery,,Conde Nast,,,,,,,,,,,"Powers, L. L.",,Kurator:in,,"Rothe, Sigrid",1193747384,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Lobby Gallery,Veranstalter,Conde Nast,,,Veranstalter,Durst Organization,Kooperationspartner,,,,,,,,,,,,,,,,,,,1,5,2008,,12,6,2008,Vernissage,7,5,2008,,16,6,2008,,25,7,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],"Tom Wesselmann Draws: A Retrospective, Haunch of Venison, 7.11.2009 - 2.1.2010",Tom Wesselmann Draws,A Retrospective,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,4021845-4,,,,,,,,,New York,4042011-5,,,,,,,"Haunch of Venison (New York, NY)",16011086-5,,,,,,,,,,,,"Wesselmann, Tom",122463757,Kurator:in,Künstler:in,"Wesselmann, Claire",1027249302,Kurator:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Haunch of Venison,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,11,2009,,2,1,2010,Vernissage,6,11,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],"Great Photographs of the 20th Century: Staged and Startled, Hasted Hunt Kraeutler, 25.3.2010 - 1.5.2010",Great Photographs of the 20th Century,Staged and Startled,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Hasted Hunt Kraeutler,,,,,,,,,,,,,"Avedon, Richard",119119307,Künstler:in,,"Barney, Tina",119545004,Künstler:in,"Callahan, Harry",Künstler:in,"Frank, Robert",Künstler:in,"Friedlander, Lee",Künstler:in,"Klein, Steven",Künstler:in,"Model, Lisette",Künstler:in,"Penn, Irving",Künstler:in,"Sternfeld, Joel",Künstler:in,"Winogrand, Garry",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hasted Hunt Kraeutler,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,25,3,2010,,1,5,2010,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],"Enrico Castlellani, Haunch of Venison, 8.5.2009 - 27.6.2009",Enrico Castlellani,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,"Haunch of Venison (New York, NY)",16011086-5,,,,,,,,,,,,"Zevi, Aachiara",,Kurator:in,,"Castellani, Enrico",118667416,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Haunch of Venison,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,8,5,2009,,27,6,2009,Private View,8,5,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],"Avner Ben-Gal, Bortolami Dayan, 12.9. - 14.10.",Avner Ben-Gal,,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,4021845-4,,,,,,,,,New York,4042011-5,,,,,,,Bortolami Dayan,"1,09E+09",,,,,,,Bortolami Gallery,,,,,"Ben-Gal, Avner",134065263,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Bortolami Dayan,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,12,9,,,14,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],"John Schuetz - Photographs, Lucas Schoormans Gallery, 22.5.2007 - 30.6.2007",John Schuetz - Photographs,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Lucas Schoormans Gallery (New York, NY)",10344862-7,,,,,,,,,,,,"Schuetz, John H.",174332939,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Lucas Schoormans Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,22,5,2007,,30,6,2007,Vernissage,22,5,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],"Ali - Underwater: Underwater Photographs of Muhammad Ali by Flip Schulke, Keith de Lellis Gallery, 25.6.2015 - 28.7.2015",Ali - Underwater,Underwater Photographs of Muhammad Ali by Flip Schulke,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Keith de Lellis Gallery,,,,,,,,,,,,,"Schulke, Flip",174270151,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Keith de Lellis Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,25,6,2015,,28,7,2015,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],"Spirit Landsapes - Tracey Moffatt, Tyler Rollins Fine Art, 24.10.2013 - 21.12.2013",Spirit Landsapes - Tracey Moffatt,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,Medienkunst,4113418-7,,,,,,,New York,4042011-5,,,,,,,Tyler Rollins Fine Art,"1,03E+09",,,,,,,,,,,,"Moffatt, Tracey",120152509,Künstler:in,,"Weir, Kathryn",1034705725,Kurator:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Tyler Rollins Fine Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,24,10,2013,,21,12,2013,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,Medienkunst,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],"Jehsong Baak - Là Ou Ailleurs, RWFA | Rick Wester Fine Art, 18.12.2009 - 21.2.2009",Jehsong Baak - Là Ou Ailleurs,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,RWFA | Rick Wester Fine Art,,,,,,,,,,,,,"Baak, Jehsong",174389531,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,RWFA | Rick Wester Fine Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,18,12,2009,,21,2,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],"Vito Acconci, Barbara Gladstone, 303 Gallery, 27.2. - 27.3.",Vito Acconci,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,Grafik,4021845-4,,,,,,,New York,4042011-5,,,,,,,"Gladstone, Barbara","1,06E+09",303 Gallery,,,,,,,,,,,"Acconci, Vito",118958143,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Barbara Gladstone,Veranstalter,303 Gallery,,,Veranstalter,,,,,,,,,,,,,,,,,,,,,27,2,,,27,3,,,,,,,,,,,20,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,Grafik,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],"Helmut Newton, Cook Fine Art, 7.3.2007 - 27.4.2007",Helmut Newton,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Cook Fine Art,,,,,,,,,,,,,"Newton, Helmut",118587536,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cook Fine Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,3,2007,,27,4,2007,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],"Theodore Roszak (1907-1981), Zabriskie Gallery, 21.10.2003 - 29.11.2003",Theodore Roszak (1907-1981),,,,,Einzelausstellung,Sonderausstellung,,,,,Grafik,4021845-4,,,,,,,,,New York,4042011-5,,,,,,,Zabriskie Gallery,5120278-5,,,,,,,,,,,,"Roszak, Theodore",119328518,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Zabriskie Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,21,10,2003,,29,11,2003,Vernissage,21,10,2003,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Grafik,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],"Ingar Krauss - Birds of Passage, Marvelli Gallery, 28.11.2007 - 5.1.2008",Ingar Krauss - Birds of Passage,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Marvelli Gallery,,,,,,,,,,,,,"Krauss, Ingar",128954213,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Marvelli Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,28,11,2007,,5,1,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],"Enoc Perez, Mitchell-Innes & Nash, 10.9.2009 - 10.10.2009",Enoc Perez,,,,,Einzelausstellung,Sonderausstellung,,,,,Malerei,4037220-0,,,,,,,,,New York,4042011-5,,,,,,,Mitchell-Innes & Nash,,,,,,,,,,,,,Exhibition Enoc Perez (2014 : Zürich),106003199X,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Mitchell-Innes & Nash,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,9,2009,,10,10,2009,Vernissage,10,9,2009,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],"An Empty Space, Akira Ikeda Gallery, 1.7.2000 - 30.6.2010",An Empty Space,,,,,Gruppenausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,Malerei,4037220-0,Objektkunst,4131740-3,Installation,1228235120,,,New York,4042011-5,Berlin,4005728-8,Jokosuka,4264872-5,Suzuka,133845-6,Akira Ikeda Gallery,10077237-7,,,,,,,,,,,,"Serra, Richard",118796267,Künstler:in,,"Richter, Gerhard",118600419,Künstler:in,"Trockel, Rosemarie",Künstler:in,"Bochner, Mel",Künstler:in,"Uecker, Günther",Künstler:in,"Stella, Frank",Künstler:in,"Knoebel, Imi",Künstler:in,"di Suvero, Mark",Künstler:in,"Kawara, On",Künstler:in,"Marden, Brice",Künstler:in,"Hawkinson, Tim",Künstler:in,"Hamilton, Ann",Künstler:in,"Haraguchi, Noriyuki",Künstler:in,"Rabinowitch, David",Künstler:in,"Steinbach, Haim",Künstler:in,"Mendoza, Ryan",Künstler:in,"Wegner, Peter",Künstler:in,"Warner, Debora",Künstler:in,"Celaya, Enrique Martínez",Künstler:in,"Friedel, Anna",Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Akira Ikeda Gallery,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,1,7,2000,,30,6,2010,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,Malerei,Objektkunst,Installation,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],"Volta, Volta NY, 7.3.2018 - 11.3.2018",Volta,,1092299041,,,Gruppenausstellung,Kunstmesse,,,Volta Art Fair,1092299041,Malerei,4037220-0,Plastik,4046277-8,Installation,1228235120,,,,,New York,4042011-5,,,,,,,Pier 90,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Volta NY,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,7,3,2018,,11,3,2018,Vernissage,7,3,2018,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Malerei,Plastik,Installation,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],"Scott B Davis - Land of Sunshine, Hous Projects, 26.6.2008 - 6.9.2008",Scott B Davis - Land of Sunshine,,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Hous Projects,,,,,,,,,,,,,"Davis, Scott B.",1101854545,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hous Projects,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,26,6,2008,,6,9,2008,Vernissage,26,6,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],"Albert Watson - Vintage Photographs: Celebrating the 20th Anniversary of Cyclops, Hasted Kraeutler, 25.10.2012 - 8.12.2012",Albert Watson - Vintage Photographs,Celebrating the 20th Anniversary of Cyclops,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"Hasted Kraeutler Gallery (New York, NY)",16154742-4,,,,,,,,,,,,"Watson, Albert",119194201,Fotograf:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Hasted Kraeutler,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,25,10,2012,,8,12,2012,Vernissage,25,10,2012,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],"New York Nocturne: The AIPAD Photography Show in New York, Park Avenue Armory, 16.4.2015 - 19.4.2015",New York Nocturne,The AIPAD Photography Show in New York,,,,Gruppenausstellung,Sonderausstellung,,,AIPAD Photography Show,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Park Avenue Armory,105364602X,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Park Avenue Armory,Veranstalter,Daniel Blau Galerie,,,Kooperationspartner,,,,,,,,,,,,,,,,,,,,,16,4,2015,,19,4,2015,Vernissage,15,4,2015,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],"The AIPAD Photography Show: The World's Premier Exposition of Fine Art. Photography with Eighty International Dealers, Association of International Photography Art Dealers, 12.2.2004 - 15.2.2004",The AIPAD Photography Show,The World's Premier Exposition of Fine Art. Photography with Eighty International Dealers,,,,Gruppenausstellung,Sonderausstellung,,,AIPAD Photography Show,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,"New York Hilton, Midtown",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Association of International Photography Art Dealers,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,12,2,2004,,15,2,2004,Vernissage,12,2,2004,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],"Sofia Valiente - Miracle Village, Park Avenue Armory, 16.4.2015 - 19.4.2015",Sofia Valiente - Miracle Village,,,,,Einzelausstellung,Sonderausstellung,,,58th World Press Photo,1008695-X,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,Park Avenue Armory,105364602X,,,,,,,,,,,,"Valiente, Sofia",1076422152,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Park Avenue Armory,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,16,4,2015,,19,4,2015,Vernissage,15,4,2015,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],"The Photography Show '06, Association of International Photography Art Dealers, 10.2.2006 - 12.2.2006",The Photography Show '06,,,,,Gruppenausstellung,Sonderausstellung,,,AIPAD Photography Show,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,,,,,,,7th Regiment Armory,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Association of International Photography Art Dealers,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,10,2,2006,,12,2,2006,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],"The Armory Show 2001, The Show Piers on the Hudson, 23.2.2001 - 26.2.2001",The Armory Show 2001,,,,,Gruppenausstellung,Kunstmesse,,,The International Fair of New Art,,Fotografie,4045895-7,Malerei,4037220-0,Bildhauerei,4046277-8,,,,,New York,4042011-5,,,,,,,The Show Piers on the Hudson,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,The Show Piers on the Hudson,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,23,2,2001,,26,2,2001,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,Malerei,Bildhauerei,,,,Englisch,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],"An American Index of the Hidden and Unfamiliar: Taryn Simon, Whitney Museum of American Art, Museum für Moderne Kunst (MMK)",An American Index of the Hidden and Unfamiliar,Taryn Simon,,,,Einzelausstellung,Sonderausstellung,,,,,Fotografie,4045895-7,,,,,,,,,New York,4042011-5,Frankfurt am Main,4018118-2,,,,,Whitney Museum of American Art,1019165-3,,,,,,,,,,,,"Simon, Taryn",129771953,Künstler:in,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Whitney Museum of American Art,Veranstalter,Museum für Moderne Kunst (MMK),,,Veranstalter,,,,,,,,,,,,,,,,,,,,,,3,2007,,,6,2007,,,,,,,9,2007,,,2,2008,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Flyer,Fotografie,,,,,,Englisch,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,New York,Blatt/unbewegtes Bild,Flyer,[Konvolut Ausstellungsephemera New York - Sonstiges],,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Museum of Modern Art,Veranstalter,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,New York,4042011-5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, diff --git a/manifestation/exhibition/package.json b/manifestation/exhibition/package.json index 0ffef78d..ec590fbd 100644 --- a/manifestation/exhibition/package.json +++ b/manifestation/exhibition/package.json @@ -3,15 +3,36 @@ "version": "1.3.0", "description": "Schema for the exhibition database", "type": "module", - "types": "./index.d.ts", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.js", + "require": "./dist/index.cjs", + "default": "./dist/index.js", + "types": "./dist/index.d.ts" + } + }, "scripts": { + "build": "tsup", + "dev": "tsup --watch", + "schema:export": "bun ./schemas/exportSchema.ts > ./schemas/jsonschema/Exhibition.schema.json", + "build:prisma": "bun ./src/createPrismaSchemal.ts > ../../prisma/exhibition.prisma", "build:doc": "mkdir -p docs/reference && jsonschema2md -o docs/reference -d schemas/jsonschema", - "build:typebox": "mkdir -p typebox && schema2typebox --input schemas/jsonschema/Exhibition.schema2.json --output typebox/generated-typebox.ts", - "build:prisma": "json-to-prisma-schema-convertor convert --inputPath='./schemas/jsonschema/test.schema.json' --outputPath='./schemas/prisma/Exhibition.prisma'" + "build:typebox": "mkdir -p typebox && schema2typebox --input schemas/jsonschema/Exhibition.schema.json --output typebox/generated-typebox.ts" }, "devDependencies": { + "@types/rdfjs__namespace": "^2.0.8", + "@slub/json-schema-prisma-utils": "workspace:*", + "@slub/edb-build-helper": "workspace:*", + "@slub/edb-data-mapping": "workspace:*", + "@slub/edb-core-types": "workspace:*", + "json-schema": "^0.4.0", "@adobe/jsonschema2md": "^7.1.5", - "schema2typebox": "^1.7.1", - "json-to-prisma-schema-convertor": "^0.1.0" + "schema2typebox": "^1.7.5" + }, + "dependencies": { + "@rdfjs/namespace": "^2.0.0" } } diff --git a/manifestation/exhibition/schemas/exportSchema.ts b/manifestation/exhibition/schemas/exportSchema.ts new file mode 100644 index 00000000..d7373729 --- /dev/null +++ b/manifestation/exhibition/schemas/exportSchema.ts @@ -0,0 +1,2 @@ +import { schema } from "../src"; +console.log(JSON.stringify(schema, null, 2)); diff --git a/manifestation/exhibition/schemas/jsonschema/Exhibition.schema.json b/manifestation/exhibition/schemas/jsonschema/Exhibition.schema.json index 2d2bd938..0a8f7cf8 100644 --- a/manifestation/exhibition/schemas/jsonschema/Exhibition.schema.json +++ b/manifestation/exhibition/schemas/jsonschema/Exhibition.schema.json @@ -19,6 +19,22 @@ "parent": { "title": "Übergeordnetes Schlagwort", "$ref": "#/$defs/Tag" + }, + "idAuthority": { + "title": "Normdatenbeziehung", + "type": "object", + "properties": { + "authority": { + "title": "Autorität", + "type": "string", + "format": "uri" + }, + "id": { + "title": "IRI", + "type": "string", + "format": "uri" + } + } } } }, @@ -35,6 +51,22 @@ "parent": { "title": "Übergeordneter Beruf", "$ref": "#/$defs/Occupation" + }, + "idAuthority": { + "title": "Normdatenbeziehung", + "type": "object", + "properties": { + "authority": { + "title": "Autorität", + "type": "string", + "format": "uri" + }, + "id": { + "title": "IRI", + "type": "string", + "format": "uri" + } + } } } }, @@ -47,6 +79,22 @@ }, "description": { "type": "string" + }, + "idAuthority": { + "title": "Normdatenbeziehung", + "type": "object", + "properties": { + "authority": { + "title": "Autorität", + "type": "string", + "format": "uri" + }, + "id": { + "title": "IRI", + "type": "string", + "format": "uri" + } + } } } }, @@ -79,6 +127,22 @@ "items": { "$ref": "#/$defs/Tag" } + }, + "idAuthority": { + "title": "Normdatenbeziehung", + "type": "object", + "properties": { + "authority": { + "title": "Autorität", + "type": "string", + "format": "uri" + }, + "id": { + "title": "IRI", + "type": "string", + "format": "uri" + } + } } } }, @@ -154,6 +218,22 @@ "image": { "type": "string", "format": "uri" + }, + "idAuthority": { + "title": "Normdatenbeziehung", + "type": "object", + "properties": { + "authority": { + "title": "Autorität", + "type": "string", + "format": "uri" + }, + "id": { + "title": "IRI", + "type": "string", + "format": "uri" + } + } } } }, @@ -168,6 +248,22 @@ }, "toDate": { "type": "integer" + }, + "idAuthority": { + "title": "Normdatenbeziehung", + "type": "object", + "properties": { + "authority": { + "title": "Autorität", + "type": "string", + "format": "uri" + }, + "id": { + "title": "IRI", + "type": "string", + "format": "uri" + } + } } } }, @@ -185,9 +281,29 @@ "description": { "type": "string" }, + "image": { + "type": "string", + "format": "uri" + }, "parent": { "title": "Übergeordneter Ort", "$ref": "#/$defs/Location" + }, + "idAuthority": { + "title": "Normdatenbeziehung", + "type": "object", + "properties": { + "authority": { + "title": "Autorität", + "type": "string", + "format": "uri" + }, + "id": { + "title": "IRI", + "type": "string", + "format": "uri" + } + } } } }, @@ -200,6 +316,22 @@ }, "description": { "type": "string" + }, + "idAuthority": { + "title": "Normdatenbeziehung", + "type": "object", + "properties": { + "authority": { + "title": "Autorität", + "type": "string", + "format": "uri" + }, + "id": { + "title": "IRI", + "type": "string", + "format": "uri" + } + } } } }, @@ -212,6 +344,22 @@ }, "description": { "type": "string" + }, + "idAuthority": { + "title": "Normdatenbeziehung", + "type": "object", + "properties": { + "authority": { + "title": "Autorität", + "type": "string", + "format": "uri" + }, + "id": { + "title": "IRI", + "type": "string", + "format": "uri" + } + } } } }, @@ -239,6 +387,22 @@ "image": { "type": "string", "format": "uri" + }, + "idAuthority": { + "title": "Normdatenbeziehung", + "type": "object", + "properties": { + "authority": { + "title": "Autorität", + "type": "string", + "format": "uri" + }, + "id": { + "title": "IRI", + "type": "string", + "format": "uri" + } + } } } }, @@ -252,10 +416,20 @@ "description": { "type": "string" }, - "tags": { - "type": "array", - "items": { - "$ref": "#/$defs/Tag" + "idAuthority": { + "title": "Normdatenbeziehung", + "type": "object", + "properties": { + "authority": { + "title": "Autorität", + "type": "string", + "format": "uri" + }, + "id": { + "title": "IRI", + "type": "string", + "format": "uri" + } } } } @@ -286,6 +460,22 @@ "image": { "type": "string", "format": "uri" + }, + "idAuthority": { + "title": "Normdatenbeziehung", + "type": "object", + "properties": { + "authority": { + "title": "Autorität", + "type": "string", + "format": "uri" + }, + "id": { + "title": "IRI", + "type": "string", + "format": "uri" + } + } } } }, @@ -298,6 +488,22 @@ }, "description": { "type": "string" + }, + "idAuthority": { + "title": "Normdatenbeziehung", + "type": "object", + "properties": { + "authority": { + "title": "Autorität", + "type": "string", + "format": "uri" + }, + "id": { + "title": "IRI", + "type": "string", + "format": "uri" + } + } } } }, @@ -332,6 +538,22 @@ "image": { "type": "string", "format": "uri" + }, + "idAuthority": { + "title": "Normdatenbeziehung", + "type": "object", + "properties": { + "authority": { + "title": "Autorität", + "type": "string", + "format": "uri" + }, + "id": { + "title": "IRI", + "type": "string", + "format": "uri" + } + } } } }, @@ -343,6 +565,22 @@ }, "role": { "$ref": "#/$defs/PersonRole" + }, + "idAuthority": { + "title": "Normdatenbeziehung", + "type": "object", + "properties": { + "authority": { + "title": "Autorität", + "type": "string", + "format": "uri" + }, + "id": { + "title": "IRI", + "type": "string", + "format": "uri" + } + } } } }, @@ -354,6 +592,22 @@ }, "role": { "$ref": "#/$defs/CorporationRole" + }, + "idAuthority": { + "title": "Normdatenbeziehung", + "type": "object", + "properties": { + "authority": { + "title": "Autorität", + "type": "string", + "format": "uri" + }, + "id": { + "title": "IRI", + "type": "string", + "format": "uri" + } + } } } }, @@ -385,7 +639,12 @@ }, "dateModifier": { "type": "integer", + "title": "Art der Zeitangabe", "oneOf": [ + { + "const": 0, + "title": "exakt" + }, { "const": 1, "title": "ca." @@ -412,7 +671,12 @@ }, "dateModifier": { "type": "integer", + "title": "Art der Zeitangabe", "oneOf": [ + { + "const": 0, + "title": "exakt" + }, { "const": 1, "title": "ca." @@ -460,6 +724,22 @@ "items": { "$ref": "#/$defs/Resource" } + }, + "idAuthority": { + "title": "Normdatenbeziehung", + "type": "object", + "properties": { + "authority": { + "title": "Autorität", + "type": "string", + "format": "uri" + }, + "id": { + "title": "IRI", + "type": "string", + "format": "uri" + } + } } } }, @@ -472,6 +752,22 @@ }, "description": { "type": "string" + }, + "idAuthority": { + "title": "Normdatenbeziehung", + "type": "object", + "properties": { + "authority": { + "title": "Autorität", + "type": "string", + "format": "uri" + }, + "id": { + "title": "IRI", + "type": "string", + "format": "uri" + } + } } } }, @@ -483,9 +779,28 @@ }, "role": { "$ref": "#/$defs/PersonRole" + }, + "idAuthority": { + "title": "Normdatenbeziehung", + "type": "object", + "properties": { + "authority": { + "title": "Autorität", + "type": "string", + "format": "uri" + }, + "id": { + "title": "IRI", + "type": "string", + "format": "uri" + } + } } }, - "required": ["person", "role"] + "required": [ + "person", + "role" + ] }, "InvolvedCorporation": { "type": "object", @@ -495,9 +810,28 @@ }, "role": { "$ref": "#/$defs/CorporationRole" + }, + "idAuthority": { + "title": "Normdatenbeziehung", + "type": "object", + "properties": { + "authority": { + "title": "Autorität", + "type": "string", + "format": "uri" + }, + "id": { + "title": "IRI", + "type": "string", + "format": "uri" + } + } } }, - "required": ["corporation", "role"] + "required": [ + "corporation", + "role" + ] }, "Genre": { "type": "object", @@ -512,6 +846,22 @@ "image": { "type": "string", "format": "uri" + }, + "idAuthority": { + "title": "Normdatenbeziehung", + "type": "object", + "properties": { + "authority": { + "title": "Autorität", + "type": "string", + "format": "uri" + }, + "id": { + "title": "IRI", + "type": "string", + "format": "uri" + } + } } } }, @@ -535,7 +885,12 @@ }, "dateModifier": { "type": "integer", + "title": "Art der Zeitangabe", "oneOf": [ + { + "const": 0, + "title": "exakt" + }, { "const": 1, "title": "ca." @@ -562,7 +917,12 @@ }, "dateModifier": { "type": "integer", + "title": "Art der Zeitangabe", "oneOf": [ + { + "const": 0, + "title": "exakt" + }, { "const": 1, "title": "ca." @@ -599,6 +959,10 @@ "$ref": "#/$defs/Genre" } }, + "parent": { + "title": "Übergeordnete Ausstellung", + "$ref": "#/$defs/Exhibition" + }, "externalId": { "type": "string", "maxLength": 50 @@ -613,6 +977,9 @@ "type": "string", "maxLength": 300 }, + "placesUnknown": { + "type": "boolean" + }, "places": { "type": "array", "items": { @@ -631,12 +998,30 @@ "$ref": "#/$defs/Tag" } }, + "exposedArtists": { + "type": "array", + "items": { + "$ref": "#/$defs/Person" + } + }, + "curators": { + "type": "array", + "items": { + "$ref": "#/$defs/Person" + } + }, "involvedPersons": { "type": "array", "items": { "$ref": "#/$defs/InvolvedPerson" } }, + "organizers": { + "type": "array", + "items": { + "$ref": "#/$defs/Corporation" + } + }, "involvedCorporations": { "type": "array", "items": { @@ -680,7 +1065,13 @@ "exponats": { "type": "array", "items": { - "$ref": "#/$defs/ExhibitionExponat" + "$ref": "#/$defs/ExhibitionExponat" + } + }, + "catalogs": { + "type": "array", + "items": { + "$ref": "#/$defs/Resource" } }, "resources": { @@ -692,6 +1083,22 @@ "image": { "type": "string", "format": "uri" + }, + "idAuthority": { + "title": "Normdatenbeziehung", + "type": "object", + "properties": { + "authority": { + "title": "Autorität", + "type": "string", + "format": "uri" + }, + "id": { + "title": "IRI", + "type": "string", + "format": "uri" + } + } } } } diff --git a/manifestation/exhibition/src/createPrismaSchemal.ts b/manifestation/exhibition/src/createPrismaSchemal.ts new file mode 100644 index 00000000..90975b85 --- /dev/null +++ b/manifestation/exhibition/src/createPrismaSchemal.ts @@ -0,0 +1,7 @@ +import { logPrismaSchemaWithPreamble } from "@slub/json-schema-prisma-utils"; +import { extendSchemaShortcut } from "@slub/json-schema-utils"; +import { schema, schemaName } from "./schema"; + +const extendedSchema = extendSchemaShortcut(schema); + +console.log(logPrismaSchemaWithPreamble(schemaName, extendedSchema)); diff --git a/manifestation/exhibition/src/index.ts b/manifestation/exhibition/src/index.ts new file mode 100644 index 00000000..ff032a76 --- /dev/null +++ b/manifestation/exhibition/src/index.ts @@ -0,0 +1,4 @@ +export * from "./schema"; +export * from "./primaryFields"; +export * from "./mappings"; +export * from "./makeStubSchema"; diff --git a/manifestation/exhibition/src/makeStubSchema.ts b/manifestation/exhibition/src/makeStubSchema.ts new file mode 100644 index 00000000..b21eed81 --- /dev/null +++ b/manifestation/exhibition/src/makeStubSchema.ts @@ -0,0 +1,72 @@ +import { JSONSchema7 } from "json-schema"; +import { + GeneratePropertiesFunction, + prepareStubbedSchema, + SchemaExpander, +} from "@slub/json-schema-utils"; + +export const schemaExpander: SchemaExpander = { + additionalProperties: { + idAuthority: { + title: "Normdatenbeziehung", + type: "object", + properties: { + authority: { + title: "Autorität", + type: "string", + format: "uri", + }, + id: { + title: "IRI", + type: "string", + format: "uri", + }, + }, + }, + }, + options: { + excludeType: ["InvolvedPerson", "InvolvedCorporation", "Workplace"], + excludeSemanticPropertiesForType: [ + "InvolvedPerson", + "InvolvedCorporation", + "AuthorityEntry", + "AuthorityEntry", + "EventType", + "ExhibitionCategory", + "SeriesType", + "Workplace", + ], + }, +}; +const makeGenSlubJSONLDSemanticProperties: ( + baseIRI: string, + entitytBaseIRI: string, +) => GeneratePropertiesFunction = + (baseIRI: string, entityBaseIRI: string) => (modelName: string) => ({ + "@type": { + const: `${baseIRI}${modelName.replace(/Stub$/, "")}`, + type: "string", + }, + "@id": { + title: entityBaseIRI, + type: "string", + }, + }); + +const genSlubJSONLDSemanticProperties = makeGenSlubJSONLDSemanticProperties( + "http://ontologies.slub-dresden.de/exhibition#", + "http://ontologies.slub-dresden.de/exhibition/entity/", +); +const genSlubRequiredProperties = (_modelName: string) => { + return ["@type", "@id"]; +}; +export const makeStubSchema: (schema: JSONSchema7) => JSONSchema7 = ( + schema, +) => { + return prepareStubbedSchema( + schema, + genSlubJSONLDSemanticProperties, + genSlubRequiredProperties, + schemaExpander.options, + ); +}; diff --git a/manifestation/exhibition/src/mappings/availableAuthorityMappings.ts b/manifestation/exhibition/src/mappings/availableAuthorityMappings.ts new file mode 100644 index 00000000..ce1fb070 --- /dev/null +++ b/manifestation/exhibition/src/mappings/availableAuthorityMappings.ts @@ -0,0 +1,16 @@ +import { wikidataMappings, wikidataTypeMap } from "./wikidataMappings"; +import { lobidMappings, lobidTypemap } from "./lobidMappings"; +import { NormDataMappings } from "@slub/edb-core-types"; + +export const availableAuthorityMappings: NormDataMappings = { + "http://www.wikidata.org": { + label: "Wikidata", + sameAsTypeMap: wikidataTypeMap, + mapping: wikidataMappings, + }, + "http://d-nb.info/gnd": { + label: "GND", + sameAsTypeMap: lobidTypemap, + mapping: lobidMappings, + }, +} as const; diff --git a/manifestation/exhibition/src/mappings/availableFlatMappings.ts b/manifestation/exhibition/src/mappings/availableFlatMappings.ts new file mode 100644 index 00000000..20e9b4c8 --- /dev/null +++ b/manifestation/exhibition/src/mappings/availableFlatMappings.ts @@ -0,0 +1,9 @@ +import { matchBasedSpreadsheetMappings_NewYork } from "./spreadSheetMappings_NewYork"; +import { AvailableFlatMappings } from "@slub/edb-global-types"; + +export const availableFlatMappings: AvailableFlatMappings = { + NewYork: { + typeName: "Exhibition", + mapping: matchBasedSpreadsheetMappings_NewYork, + }, +} as const; diff --git a/manifestation/exhibition/src/mappings/index.ts b/manifestation/exhibition/src/mappings/index.ts new file mode 100644 index 00000000..b4ac57d5 --- /dev/null +++ b/manifestation/exhibition/src/mappings/index.ts @@ -0,0 +1,4 @@ +export * from "./lobidMappings"; +export * from "./wikidataMappings"; +export * from "./availableFlatMappings"; +export * from "./availableAuthorityMappings"; diff --git a/apps/exhibition-live/components/config/lobidMappings.ts b/manifestation/exhibition/src/mappings/lobidMappings.ts similarity index 76% rename from apps/exhibition-live/components/config/lobidMappings.ts rename to manifestation/exhibition/src/mappings/lobidMappings.ts index e1ef604b..9ae37387 100644 --- a/apps/exhibition-live/components/config/lobidMappings.ts +++ b/manifestation/exhibition/src/mappings/lobidMappings.ts @@ -1,8 +1,174 @@ -import { sladb } from "../form/formConfigs"; -import { +import namespace from "@rdfjs/namespace"; +import type { DeclarativeMapping, DeclarativeMappings, -} from "../utils/mapping/mappingStrategies"; +} from "@slub/edb-data-mapping"; +export const sladb = namespace("http://ontologies.slub-dresden.de/exhibition#"); + +export const locationDeclarativeMapping: DeclarativeMappings = [ + { + source: { + path: "preferredName", + }, + target: { + path: "title", + }, + }, + { + source: { + path: "biographicalOrHistoricalInformation", + }, + target: { + path: "description", + }, + mapping: { + strategy: { + id: "concatenate", + options: { + separator: "\n", + }, + }, + }, + }, + { + source: { + path: "depiction.0.thumbnail", + }, + target: { + path: "image", + }, + }, + { + source: { + path: "", + }, + target: { + path: "idAuthority.authority", + }, + mapping: { + strategy: { + id: "constant", + options: { + value: "http://d-nb.info/gnd", + }, + }, + }, + }, + { + source: { + path: "id", + }, + target: { + path: "idAuthority.id", + }, + }, +]; + +export const corporateBodyDeclarativeMapping: DeclarativeMappings = [ + { + source: { + path: "preferredName", + expectedSchema: { + type: "string", + }, + }, + target: { + path: "name", + }, + }, + { + source: { + path: "variantName", + }, + target: { + path: "nameVariant", + }, + mapping: { + strategy: { + id: "append", + }, + }, + }, + { + source: { + path: "", + }, + target: { + path: "idAuthority.authority", + }, + mapping: { + strategy: { + id: "constant", + options: { + value: "http://d-nb.info/gnd", + }, + }, + }, + }, + { + source: { + path: "id", + }, + target: { + path: "idAuthority.id", + }, + }, + { + source: { + path: "spatialAreaOfActivity", + }, + target: { + path: "locations", + }, + mapping: { + strategy: { + id: "createEntity", + options: { + typeIRI: sladb("Location").value, + typeName: "Location", + subFieldMapping: { + fromEntity: locationDeclarativeMapping, + }, + }, + }, + }, + }, +]; + +export const tagMapping: DeclarativeMappings = [ + { + source: { + path: "preferredName", + }, + target: { + path: "title", + }, + }, + { + source: { + path: "", + }, + target: { + path: "idAuthority.authority", + }, + mapping: { + strategy: { + id: "constant", + options: { + value: "http://d-nb.info/gnd", + }, + }, + }, + }, + { + source: { + path: "id", + }, + target: { + path: "idAuthority.id", + }, + }, +]; export const exhibitionDeclarativeMapping: DeclarativeMappings = [ { @@ -16,12 +182,28 @@ export const exhibitionDeclarativeMapping: DeclarativeMappings = [ path: "title", }, }, + { + source: { + path: "", + }, + target: { + path: "idAuthority.authority", + }, + mapping: { + strategy: { + id: "constant", + options: { + value: "http://d-nb.info/gnd", + }, + }, + }, + }, { source: { path: "id", }, target: { - path: "idAuthority.@id", + path: "idAuthority.id", }, }, { @@ -135,25 +317,9 @@ export const exhibitionDeclarativeMapping: DeclarativeMappings = [ id: "createEntity", options: { typeIRI: sladb("Location").value, + typeName: "Location", subFieldMapping: { - fromEntity: [ - { - source: { - path: "label", - }, - target: { - path: "title", - }, - }, - { - source: { - path: "id", - }, - target: { - path: "idAuthority.@id", - }, - }, - ], + fromEntity: locationDeclarativeMapping, }, }, }, @@ -204,24 +370,7 @@ export const exhibitionDeclarativeMapping: DeclarativeMappings = [ typeIRI: sladb("Corporation").value, typeName: "Corporation", subFieldMapping: { - fromEntity: [ - { - source: { - path: "label", - }, - target: { - path: "name", - }, - }, - { - source: { - path: "id", - }, - target: { - path: "idAuthority.@id", - }, - }, - ], + fromEntity: corporateBodyDeclarativeMapping, }, }, }, @@ -235,52 +384,39 @@ export const exhibitionDeclarativeMapping: DeclarativeMappings = [ }, { source: { - path: "hierarchicalSuperiorOfTheConferenceOrEvent.0", + path: "topic", }, target: { - path: "parent", + path: "tag", }, mapping: { strategy: { id: "createEntity", options: { - typeIRI: sladb("Exhibition").value, - typeName: "Exhibition", - subFieldMapping: {}, + typeIRI: sladb("Tag").value, + typeName: "Tag", + subFieldMapping: { + fromEntity: tagMapping, + }, }, }, }, }, { source: { - path: "topic", + path: "hierarchicalSuperiorOfTheConferenceOrEvent.0", }, target: { - path: "tag", + path: "parent", }, mapping: { strategy: { id: "createEntity", options: { + typeIRI: sladb("Exhibition").value, + typeName: "Exhibition", subFieldMapping: { - fromEntity: [ - { - source: { - path: "label", - }, - target: { - path: "title", - }, - }, - { - source: { - path: "id", - }, - target: { - path: "idAuthority.@id", - }, - }, - ], + fromEntity: "self", }, }, }, @@ -288,7 +424,7 @@ export const exhibitionDeclarativeMapping: DeclarativeMappings = [ }, ]; -export const locationDeclarativeMapping: DeclarativeMappings = [ +export const event2exhibitionSeriesDeclarativeMapping: DeclarativeMappings = [ { source: { path: "preferredName", @@ -299,53 +435,26 @@ export const locationDeclarativeMapping: DeclarativeMappings = [ }, { source: { - path: "biographicalOrHistoricalInformation", + path: "", }, target: { - path: "description", + path: "idAuthority.authority", }, mapping: { strategy: { - id: "concatenate", + id: "constant", options: { - separator: "\n", + value: "http://d-nb.info/gnd", }, }, }, }, - { - source: { - path: "depiction", - }, - target: { - path: "image", - }, - }, { source: { path: "id", }, target: { - path: "idAuthority.@id", - }, - }, -]; - -export const event2exhibitionSeriesDeclarativeMapping: DeclarativeMappings = [ - { - source: { - path: "preferredName", - }, - target: { - path: "title", - }, - }, - { - source: { - path: "id", - }, - target: { - path: "idAuthority.@id", + path: "idAuthority.id", }, }, { @@ -377,25 +486,9 @@ export const event2exhibitionSeriesDeclarativeMapping: DeclarativeMappings = [ options: { single: true, typeIRI: sladb("Location").value, + typeName: "Location", subFieldMapping: { - fromEntity: [ - { - source: { - path: "label", - }, - target: { - path: "title", - }, - }, - { - source: { - path: "id", - }, - target: { - path: "idAuthority.@id", - }, - }, - ], + fromEntity: locationDeclarativeMapping, }, }, }, @@ -412,12 +505,28 @@ export const occupationDeclarativeMapping: DeclarativeMappings = [ path: "title", }, }, + { + source: { + path: "", + }, + target: { + path: "idAuthority.authority", + }, + mapping: { + strategy: { + id: "constant", + options: { + value: "http://d-nb.info/gnd", + }, + }, + }, + }, { source: { path: "id", }, target: { - path: "idAuthority.@id", + path: "idAuthority.id", }, }, ]; @@ -530,6 +639,7 @@ export const personDeclarativeMapping: DeclarativeMappings = [ id: "createEntity", options: { typeIRI: sladb("Occupation").value, + typeName: "Occupation", subFieldMapping: { fromEntity: occupationDeclarativeMapping, }, @@ -550,7 +660,7 @@ export const personDeclarativeMapping: DeclarativeMappings = [ path: "id", }, target: { - path: "idAuthority.@id", + path: "idAuthority.id", }, }, ]; @@ -572,7 +682,7 @@ export const corporateBody2PlaceDeclarativeMapping: DeclarativeMappings = [ path: "id", }, target: { - path: "idAuthority.@id", + path: "idAuthority.id", }, }, { @@ -588,102 +698,15 @@ export const corporateBody2PlaceDeclarativeMapping: DeclarativeMappings = [ options: { single: true, typeIRI: sladb("Location").value, + typeName: "Location", subFieldMapping: { - fromEntity: [ - { - source: { - path: "label", - }, - target: { - path: "title", - }, - }, - { - source: { - path: "id", - }, - target: { - path: "idAuthority.@id", - }, - }, - ], - }, - }, - }, - }, - }, -]; -export const corporateBodyDeclarativeMapping: DeclarativeMappings = [ - { - source: { - path: "preferredName", - expectedSchema: { - type: "string", - }, - }, - target: { - path: "name", - }, - }, - { - source: { - path: "variantName", - }, - target: { - path: "nameVariant", - }, - mapping: { - strategy: { - id: "append", - }, - }, - }, - { - source: { - path: "id", - }, - target: { - path: "idAuthority.@id", - }, - }, - { - source: { - path: "spatialAreaOfActivity", - }, - target: { - path: "locations", - }, - mapping: { - strategy: { - id: "createEntity", - options: { - typeIRI: sladb("Location").value, - subFieldMapping: { - fromEntity: [ - { - source: { - path: "label", - }, - target: { - path: "title", - }, - }, - { - source: { - path: "id", - }, - target: { - path: "idAuthority.@id", - }, - }, - ], + fromEntity: locationDeclarativeMapping, }, }, }, }, }, ]; - export const workDeclarativeMapping: DeclarativeMappings = [ { source: { @@ -706,28 +729,9 @@ export const workDeclarativeMapping: DeclarativeMappings = [ }, ]; -export const tagMapping: DeclarativeMappings = [ - { - source: { - path: "preferredName", - }, - target: { - path: "title", - }, - }, - { - source: { - path: "id", - }, - target: { - path: "idAuthority.@id", - }, - }, -]; - export const lobidTypemap: Record = { Exhibition: "ConferenceOrEvent", - ExhibitionSeries: "ConferenceOrEvent", + ExhibitionSeries: "SeriesOfConferenceOrEvent", Person: "DifferentiatedPerson", Corporation: "CorporateBody", Place: "CorporateBody", @@ -737,7 +741,7 @@ export const lobidTypemap: Record = { Tag: "SubjectHeading", Genre: "SubjectHeading", }; -export const declarativeMappings: DeclarativeMapping = { +export const lobidMappings: DeclarativeMapping = { Exhibition: exhibitionDeclarativeMapping, Person: personDeclarativeMapping, Corporation: corporateBodyDeclarativeMapping, diff --git a/manifestation/exhibition/src/mappings/spreadSheetMappings_NewYork.ts b/manifestation/exhibition/src/mappings/spreadSheetMappings_NewYork.ts new file mode 100644 index 00000000..e456a5c1 --- /dev/null +++ b/manifestation/exhibition/src/mappings/spreadSheetMappings_NewYork.ts @@ -0,0 +1,299 @@ +import { DeclarativeMatchBasedFlatMappings } from "@slub/edb-data-mapping"; +import namespace from "@rdfjs/namespace"; + +const BASE_IRI = "http://ontologies.slub-dresden.de/exhibition#"; +const sladb = namespace(BASE_IRI); +const gndBaseIRI = "https://d-nb.info/gnd/"; +export const matchBasedSpreadsheetMappings_NewYork = [ + { + id: "Ausstellungstitel", + source: { + columns: { + title: ["Ausstellungstitel 1"], + }, + }, + target: { + path: "title", + }, + }, + { + id: "Genre", + source: { + columns: { + titlePattern: "Genre {{=it.i + 1}}", + amount: 5, + includeRightNeighbours: 1, + }, + }, + target: { + path: "exhibitionGenre", + }, + mapping: { + strategy: { + id: "createEntityWithAuthoritativeLink", + options: { + typeIRI: sladb("Genre").value, + typeName: "Genre", + mainProperty: { + offset: 0, + }, + authorityFields: [ + { + offset: 1, + authorityLinkPrefix: gndBaseIRI, + }, + ], + }, + }, + }, + }, + { + id: "geografischer Ort", + source: { + columns: { + titlePattern: "Ort der Ausstellung (geografisch) {{=it.i + 1}}", + amount: 1, + includeRightNeighbours: 1, + }, + }, + target: { + path: "locations", + }, + mapping: { + strategy: { + id: "createEntityWithAuthoritativeLink", + options: { + typeIRI: sladb("Location").value, + typeName: "Location", + mainProperty: { + offset: 0, + }, + authorityFields: [ + { + offset: 1, + authorityLinkPrefix: gndBaseIRI, + }, + ], + }, + }, + }, + }, + { + id: "institutioneller Ort", + source: { + columns: { + titlePattern: "Ort der Ausstellung (Institution) {{=it.i + 1}}", + amount: 1, + includeRightNeighbours: 1, + }, + }, + target: { + path: "places", + }, + mapping: { + strategy: { + id: "createEntityWithAuthoritativeLink", + options: { + typeIRI: sladb("Place").value, + typeName: "Place", + mainProperty: { + offset: 0, + }, + authorityFields: [ + { + offset: 1, + authorityLinkPrefix: gndBaseIRI, + }, + ], + }, + }, + }, + }, + { + id: "Beteiligte Person", + source: { + columns: { + titlePattern: "Beteiligte Person {{=it.i + 3}}", + amount: 22, + includeRightNeighbours: 1, + }, + }, + target: { + path: "involvedPersons", + }, + mapping: { + strategy: { + id: "createEntityWithReificationFromString", + options: { + typeIRI: sladb("InvolvedPerson").value, + typeName: "InvolvedPerson", + mainProperty: { + property: "person", + offset: 0, + mapping: { + strategy: { + id: "createEntityFromString", + options: { + typeIRI: sladb("Person").value, + typeName: "Person", + }, + }, + }, + }, + statementProperties: [ + { + property: "role", + offset: 1, + mapping: { + strategy: { + id: "createEntityFromString", + options: { + typeIRI: sladb("PersonRole").value, + typeName: "PersonRole", + }, + }, + }, + }, + ], + }, + }, + }, + }, + { + id: "Beteiligte Person GND", + source: { + columns: { + titlePattern: "Beteiligte Person {{=it.i + 1}} (Name)", + amount: 4, + includeRightNeighbours: 3, + }, + }, + target: { + path: "involvedPersons", + }, + mapping: { + strategy: { + id: "createEntityWithReificationFromString", + options: { + typeIRI: sladb("InvolvedPerson").value, + typeName: "InvolvedPerson", + mainProperty: { + property: "person", + mapping: { + strategy: { + id: "createEntityWithAuthoritativeLink", + options: { + typeIRI: sladb("Person").value, + typeName: "Person", + mainProperty: { + offset: 0, + }, + authorityFields: [ + { + offset: 1, + authorityLinkPrefix: gndBaseIRI, + }, + ], + }, + }, + }, + }, + statementProperties: [ + { + property: "role", + offset: 2, + mapping: { + strategy: { + id: "createEntityFromString", + options: { + typeIRI: sladb("PersonRole").value, + typeName: "PersonRole", + }, + }, + }, + }, + ], + }, + }, + }, + }, + { + id: "Beteiligte Körperschaft", + source: { + columns: { + titlePattern: "Beteiligte Körperschaft {{=it.i + 3}}", + amount: 6, + includeRightNeighbours: 1, + }, + }, + target: { + path: "involvedCorporations", + }, + mapping: { + strategy: { + id: "createEntityWithReificationFromString", + options: { + typeIRI: sladb("InvolvedCorporation").value, + typeName: "InvolvedCorporation", + mainProperty: { + property: "corporation", + }, + statementProperties: [ + { + property: "role", + mapping: { + strategy: { + id: "createEntityFromString", + options: { + typeIRI: sladb("CorporationRole").value, + typeName: "CorporationRole", + }, + }, + }, + }, + ], + }, + }, + }, + }, + { + id: "Ausstellungsenddatum", + source: { + columns: { + title: ["Ausstellungsdatum (...bis) 1"], + includeRightNeighbours: 3, + }, + }, + target: { + path: "endDate", + }, + mapping: { + strategy: { + id: "arrayToAdbDate", + options: { + offset: 1, + }, + }, + }, + }, + { + id: "Ausstellungsstartdatum", + source: { + columns: { + title: ["Ausstellungsdatum (von...) 1"], + includeRightNeighbours: 3, + }, + }, + target: { + path: "startDate", + }, + mapping: { + strategy: { + id: "arrayToAdbDate", + options: { + offset: 1, + }, + }, + }, + }, +] as DeclarativeMatchBasedFlatMappings; diff --git a/manifestation/exhibition/src/mappings/wikidataMappings.ts b/manifestation/exhibition/src/mappings/wikidataMappings.ts new file mode 100644 index 00000000..b2845ce9 --- /dev/null +++ b/manifestation/exhibition/src/mappings/wikidataMappings.ts @@ -0,0 +1,710 @@ +import { + DeclarativeMapping, + DeclarativeMappings, +} from "@slub/edb-data-mapping"; +import { sladb } from "./lobidMappings"; + +const createWikidataMappings = ( + language: string | string[], +): Record => { + const createLanguageSpecificMappings = ( + labelField: string = "title", + ): DeclarativeMappings => { + return [ + { + source: { + path: `$.labels.${language}.value`, + }, + target: { + path: labelField, + }, + mapping: { + strategy: { + id: "takeFirst", + }, + }, + }, + { + source: { + path: `$.descriptions.${language}.value`, + }, + target: { + path: "description", + }, + mapping: { + strategy: { + id: "takeFirst", + }, + }, + }, + ]; + }; + + const wikidataLocationMapping: DeclarativeMappings = [ + ...createLanguageSpecificMappings("title"), + { + source: { + path: "$.claims.P18[*].mainsnak.datavalue.value", + }, + target: { + path: "image", + }, + mapping: { + strategy: { + id: "withDotTemplate", + options: { + single: true, + template: + "http://commons.wikimedia.org/wiki/Special:FilePath/{{value}}", + }, + }, + }, + }, + { + source: { + path: "$.claims.P131[*].mainsnak.datavalue.value.id", + }, + target: { + path: "parent", + }, + mapping: { + strategy: { + id: "createEntityWithAuthoritativeLink", + options: { + single: true, + typeIRI: sladb("Location").value, + typeName: "Location", + mainProperty: { + offset: 0, + }, + authorityFields: [ + { + offset: 0, + authorityLinkPrefix: "http://www.wikidata.org/entity/", + authorityIRI: "http://www.wikidata.org", + }, + ], + }, + }, + }, + }, + { + source: { + path: "$.claims.P1448[*].mainsnak.datavalue.value.text", + }, + target: { + path: "titleVariants", + }, + mapping: { + strategy: { + id: "concatenate", + options: { + separator: ", ", + }, + }, + }, + }, + ]; + + const wikidataExhibitionSeriesMapping: DeclarativeMappings = [ + ...createLanguageSpecificMappings("title"), + { + source: { + path: "$.claims.P18[*].mainsnak.datavalue.value", + }, + target: { + path: "image", + }, + mapping: { + strategy: { + id: "withDotTemplate", + options: { + single: true, + template: + "http://commons.wikimedia.org/wiki/Special:FilePath/{{value}}", + }, + }, + }, + }, + { + source: { + path: "$.claims.P131[*].mainsnak.datavalue.value.id", + }, + target: { + path: "location", + }, + mapping: { + strategy: { + id: "createEntityWithAuthoritativeLink", + options: { + single: true, + typeIRI: sladb("Location").value, + typeName: "Location", + mainProperty: { + offset: 0, + }, + authorityFields: [ + { + offset: 0, + authorityLinkPrefix: "http://www.wikidata.org/entity/", + authorityIRI: "http://www.wikidata.org", + }, + ], + }, + }, + }, + }, + { + source: { + path: "$.claims.P31[*].mainsnak.datavalue.value.id", + }, + target: { + path: "seriesType", + }, + mapping: { + strategy: { + id: "createEntityWithAuthoritativeLink", + options: { + single: true, + typeIRI: sladb("SeriesType").value, + typeName: "SeriesType", + mainProperty: { + offset: 0, + }, + authorityFields: [ + { + offset: 0, + authorityLinkPrefix: "http://www.wikidata.org/entity/", + authorityIRI: "http://www.wikidata.org", + }, + ], + }, + }, + }, + }, + { + source: { + path: "$.claims.P361[*].mainsnak.datavalue.value.id", + }, + target: { + path: "parent", + }, + mapping: { + strategy: { + id: "createEntityWithAuthoritativeLink", + options: { + single: true, + typeIRI: sladb("ExhibitionSeries").value, + typeName: "ExhibitionSeries", + mainProperty: { + offset: 0, + }, + authorityFields: [ + { + offset: 0, + authorityLinkPrefix: "http://www.wikidata.org/entity/", + authorityIRI: "http://www.wikidata.org", + }, + ], + }, + }, + }, + }, + { + source: { + path: "$.claims.P921[*].mainsnak.datavalue.value.id", + }, + target: { + path: "tags", + }, + mapping: { + strategy: { + id: "createEntityWithAuthoritativeLink", + options: { + typeIRI: sladb("Tag").value, + typeName: "Tag", + mainProperty: { + offset: 0, + }, + authorityFields: [ + { + offset: 0, + authorityLinkPrefix: "http://www.wikidata.org/entity/", + authorityIRI: "http://www.wikidata.org", + }, + ], + }, + }, + }, + }, + ]; + + const wikidataExhibitionMapping: DeclarativeMappings = [ + ...createLanguageSpecificMappings("title"), + { + source: { + path: "$.claims.P18[*].mainsnak.datavalue.value", + }, + target: { + path: "image", + }, + mapping: { + strategy: { + id: "withDotTemplate", + options: { + single: true, + template: + "http://commons.wikimedia.org/wiki/Special:FilePath/{{value}}", + }, + }, + }, + }, + { + source: { + path: "$.claims.P276[*].mainsnak.datavalue.value.id", + }, + target: { + path: "locations", + }, + mapping: { + strategy: { + id: "createEntityWithAuthoritativeLink", + options: { + typeIRI: sladb("Location").value, + typeName: "Location", + mainProperty: { + offset: 0, + }, + authorityFields: [ + { + offset: 0, + authorityLinkPrefix: "http://www.wikidata.org/entity/", + authorityIRI: "http://www.wikidata.org", + }, + ], + }, + }, + }, + }, + { + source: { + path: "$.claims.P580[*].mainsnak.datavalue.value.time", + }, + target: { + path: "startDate.dateValue", + }, + mapping: { + strategy: { + id: "dateStringToSpecialInt", + }, + }, + }, + { + source: { + path: "$.claims.P582[*].mainsnak.datavalue.value.time", + }, + target: { + path: "endDate.dateValue", + }, + mapping: { + strategy: { + id: "dateStringToSpecialInt", + }, + }, + }, + { + source: { + path: "$.claims.P1545[*].mainsnak.datavalue.value", + }, + target: { + path: "seriesOrdinal", + }, + mapping: { + strategy: { + id: "takeFirst", + }, + }, + }, + { + source: { + path: "$.claims.P361[*].mainsnak.datavalue.value.id", + }, + target: { + path: "parent", + }, + mapping: { + strategy: { + id: "createEntityWithAuthoritativeLink", + options: { + single: true, + typeIRI: sladb("ExhibitionSeries").value, + typeName: "ExhibitionSeries", + mainProperty: { + offset: 0, + }, + authorityFields: [ + { + offset: 0, + authorityLinkPrefix: "http://www.wikidata.org/entity/", + authorityIRI: "http://www.wikidata.org", + }, + ], + }, + }, + }, + }, + { + source: { + path: "$.claims.P856[*].mainsnak.datavalue.value", + }, + target: { + path: "website", + }, + mapping: { + strategy: { + id: "takeFirst", + }, + }, + }, + ]; + + const wikidataPersonMapping: DeclarativeMappings = [ + ...createLanguageSpecificMappings("name"), + { + source: { + path: "$.claims.P569[*].mainsnak.datavalue.value.time", + }, + target: { + path: "birthDate", + }, + mapping: { + strategy: { + id: "dateStringToSpecialInt", + }, + }, + }, + { + source: { + path: "$.claims.P570[*].mainsnak.datavalue.value.time", + }, + target: { + path: "deathDate", + }, + mapping: { + strategy: { + id: "dateStringToSpecialInt", + }, + }, + }, + { + source: { + path: "$.claims.P106[*].mainsnak.datavalue.value.id", + }, + target: { + path: "profession", + }, + mapping: { + strategy: { + id: "createEntityWithAuthoritativeLink", + options: { + typeIRI: sladb("Occupation").value, + typeName: "Occupation", + mainProperty: { + offset: 0, + }, + authorityFields: [ + { + offset: 0, + authorityLinkPrefix: "http://www.wikidata.org/entity/", + authorityIRI: "http://www.wikidata.org", + }, + ], + }, + }, + }, + }, + { + source: { + path: "$.labels[*].value", + }, + target: { + path: "nameVariant", + }, + }, + { + source: { + path: "$.claims.P21[*].mainsnak.datavalue.value.id", + }, + target: { + path: "gender", + }, + mapping: { + strategy: { + id: "createEntityWithAuthoritativeLink", + options: { + single: true, + typeIRI: sladb("Gender").value, + typeName: "Gender", + mainProperty: { + offset: 0, + }, + authorityFields: [ + { + offset: 0, + authorityLinkPrefix: "http://www.wikidata.org/entity/", + authorityIRI: "http://www.wikidata.org", + }, + ], + }, + }, + }, + }, + { + source: { + path: "$.claims.P570", + }, + target: { + path: "personDeceased", + }, + mapping: { + strategy: { + id: "exists", + }, + }, + }, + { + source: { + path: "$.id", + }, + target: { + path: "externalId", + }, + mapping: { + strategy: { + id: "takeFirst", + }, + }, + }, + { + source: { + path: "$.claims.P463[*].mainsnak.datavalue.value.id", + }, + target: { + path: "memberOfCorp", + }, + mapping: { + strategy: { + id: "createEntityWithAuthoritativeLink", + options: { + typeIRI: sladb("Corporation").value, + typeName: "Corporation", + mainProperty: { + offset: 0, + }, + authorityFields: [ + { + offset: 0, + authorityLinkPrefix: "http://www.wikidata.org/entity/", + authorityIRI: "http://www.wikidata.org", + }, + ], + }, + }, + }, + }, + { + source: { + path: "$.claims.P18[*].mainsnak.datavalue.value", + }, + target: { + path: "image", + }, + mapping: { + strategy: { + id: "withDotTemplate", + options: { + single: true, + template: + "http://commons.wikimedia.org/wiki/Special:FilePath/{{value}}", + }, + }, + }, + }, + ]; + + const wikidataOccupationMapping: DeclarativeMappings = [ + ...createLanguageSpecificMappings("title"), + { + source: { + path: "$.claims.P279[*].mainsnak.datavalue.value.id", + }, + target: { + path: "parent", + }, + mapping: { + strategy: { + id: "createEntityWithAuthoritativeLink", + options: { + single: true, + typeIRI: sladb("Occupation").value, + typeName: "Occupation", + mainProperty: { + offset: 0, + }, + authorityFields: [ + { + offset: 0, + authorityLinkPrefix: "http://www.wikidata.org/entity/", + authorityIRI: "http://www.wikidata.org", + }, + ], + }, + }, + }, + }, + { + source: { + path: "$.id", + }, + target: { + path: "externalId", + }, + mapping: { + strategy: { + id: "takeFirst", + }, + }, + }, + { + source: { + path: "$.claims.P18[*].mainsnak.datavalue.value", + }, + target: { + path: "image", + }, + mapping: { + strategy: { + id: "withDotTemplate", + options: { + single: true, + template: + "http://commons.wikimedia.org/wiki/Special:FilePath/{{value}}", + }, + }, + }, + }, + ]; + + const wikidataPlaceMapping: DeclarativeMappings = [ + ...createLanguageSpecificMappings("title"), + { + source: { + path: "$.aliases.de[*].value", + }, + target: { + path: "titleVariants", + }, + mapping: { + strategy: { + id: "concatenate", + options: { + separator: ", ", + }, + }, + }, + }, + { + source: { + path: "$.claims.P131[*].mainsnak.datavalue.value.id", + }, + target: { + path: "location", + }, + mapping: { + strategy: { + id: "createEntityWithAuthoritativeLink", + options: { + single: true, + typeIRI: sladb("Location").value, + typeName: "Location", + mainProperty: { + offset: 0, + }, + authorityFields: [ + { + offset: 0, + authorityLinkPrefix: "http://www.wikidata.org/entity/", + authorityIRI: "http://www.wikidata.org", + }, + ], + }, + }, + }, + }, + { + source: { + path: "$.claims.P361[*].mainsnak.datavalue.value.id", + }, + target: { + path: "parent", + }, + mapping: { + strategy: { + id: "createEntityWithAuthoritativeLink", + options: { + single: true, + typeIRI: sladb("Place").value, + typeName: "Place", + mainProperty: { + offset: 0, + }, + authorityFields: [ + { + offset: 0, + authorityLinkPrefix: "http://www.wikidata.org/entity/", + authorityIRI: "http://www.wikidata.org", + }, + ], + }, + }, + }, + }, + { + source: { + path: "$.claims.P18[*].mainsnak.datavalue.value", + }, + target: { + path: "image", + }, + mapping: { + strategy: { + id: "withDotTemplate", + options: { + single: true, + template: + "http://commons.wikimedia.org/wiki/Special:FilePath/{{value}}", + }, + }, + }, + }, + ]; + + return { + Location: wikidataLocationMapping, + ExhibitionSeries: wikidataExhibitionSeriesMapping, + Exhibition: wikidataExhibitionMapping, + Person: wikidataPersonMapping, + Occupation: wikidataOccupationMapping, + Place: wikidataPlaceMapping, + }; +}; + +export const wikidataMappings = createWikidataMappings("de"); + +export const wikidataTypeMap = { + Person: "Q5", + Corporation: "Q43229", + Place: "Q2221906", + Location: "Q2221906", + Occupation: "Q28640", // Add this line for Occupation +}; diff --git a/apps/exhibition-live/components/config/primaryFields.ts b/manifestation/exhibition/src/primaryFields.ts similarity index 65% rename from apps/exhibition-live/components/config/primaryFields.ts rename to manifestation/exhibition/src/primaryFields.ts index 1394cc57..0dac986e 100644 --- a/apps/exhibition-live/components/config/primaryFields.ts +++ b/manifestation/exhibition/src/primaryFields.ts @@ -1,15 +1,17 @@ -import exhibitionSchema from "../../public/schema/Exhibition.schema.json"; -import { PrimaryField, PrimaryFieldExtract } from "../utils/types"; +import { + PrimaryField, + PrimaryFieldDeclaration, + PrimaryFieldExtractDeclaration, +} from "@slub/edb-core-types"; +import { schema } from "./schema"; +import { defs } from "@slub/json-schema-utils"; -type ExhibitionPrimaryFieldDeclaration = { - //typeof keys of exhibitionSchema.$defs - [typeName in keyof typeof exhibitionSchema.$defs]: PrimaryField; -}; +type ExhibitionPrimaryFieldDeclaration = PrimaryFieldDeclaration; -type ExhibitionPrimaryFieldExtractDeclaration = { - //typeof keys of exhibitionSchema.$defs - [typeName in keyof typeof exhibitionSchema.$defs]: PrimaryFieldExtract; -}; +type ExhibitionPrimaryFieldExtractDeclaration = PrimaryFieldExtractDeclaration< + any, + string +>; const defaultMapping: PrimaryField = { label: "title", @@ -23,6 +25,9 @@ const defaultMappingWithImg: PrimaryField = { }; export const primaryFields: Partial = { + ...Object.fromEntries( + Object.keys(defs(schema)).map((key) => [key, defaultMapping]), + ), Exhibition: defaultMappingWithImg, Tag: defaultMappingWithImg, Person: { @@ -37,13 +42,7 @@ export const primaryFields: Partial = { Genre: defaultMappingWithImg, Place: defaultMappingWithImg, Location: defaultMappingWithImg, - CorporationRole: defaultMapping, - PersonRole: defaultMapping, ExhibitionSeries: defaultMapping, - SeriesType: defaultMapping, - EventType: defaultMapping, - Resource: defaultMapping, - Occupation: defaultMapping, ExhibitionCategory: { ...defaultMapping, label: "name", diff --git a/manifestation/exhibition/src/schema.ts b/manifestation/exhibition/src/schema.ts new file mode 100644 index 00000000..5e732447 --- /dev/null +++ b/manifestation/exhibition/src/schema.ts @@ -0,0 +1,762 @@ +import { JSONSchema7 } from "json-schema"; +import { extendDefinitionsWithProperties } from "@slub/json-schema-utils"; +import { schemaExpander } from "./makeStubSchema"; + +export const schemaName = "exhibition"; + +const rawSchema: JSONSchema7 = { + $schema: "http://json-schema.org/draft-07/schema#", + $id: "https://schema.adb.arthistoricum.net/exhibition#v1", + title: "SLUB Ausstellungsdatenbank", + $defs: { + Tag: { + type: "object", + properties: { + title: { + type: "string", + maxLength: 200, + }, + description: { + type: "string", + }, + image: { + type: "string", + format: "uri", + }, + parent: { + title: "Übergeordnetes Schlagwort", + $ref: "#/$defs/Tag", + }, + }, + }, + Occupation: { + type: "object", + properties: { + title: { + type: "string", + maxLength: 200, + }, + description: { + type: "string", + }, + parent: { + title: "Übergeordneter Beruf", + $ref: "#/$defs/Occupation", + }, + }, + }, + SeriesType: { + type: "object", + properties: { + title: { + type: "string", + maxLength: 200, + }, + description: { + type: "string", + }, + }, + }, + ExhibitionSeries: { + type: "object", + properties: { + title: { + type: "string", + maxLength: 200, + }, + description: { + type: "string", + }, + parent: { + title: "Übergeordnete Ausstellungsreihe", + $ref: "#/$defs/ExhibitionSeries", + }, + seriesType: { + $ref: "#/$defs/SeriesType", + }, + timeSeries: { + type: "string", + maxLength: 200, + }, + location: { + $ref: "#/$defs/Location", + }, + tags: { + type: "array", + items: { + $ref: "#/$defs/Tag", + }, + }, + }, + }, + Person: { + type: "object", + properties: { + name: { + type: "string", + maxLength: 200, + }, + description: { + type: "string", + }, + birthDate: { + type: "integer", + }, + deathDate: { + type: "integer", + }, + profession: { + type: "array", + items: { + $ref: "#/$defs/Occupation", + }, + }, + nameVariant: { + type: "array", + items: { + type: "string", + }, + }, + gender: { + type: "string", + maxLength: 1, + oneOf: [ + { + const: "m", + title: "männlich", + }, + { + const: "f", + title: "weiblich", + }, + { + const: "d", + title: "divers", + }, + { + const: "u", + title: "unbekannt", + }, + ], + }, + personDeceased: { + type: "boolean", + }, + externalId: { + type: "string", + maxLength: 50, + }, + workplace: { + type: "array", + items: { + $ref: "#/$defs/Workplace", + }, + }, + memberOfCorp: { + type: "array", + items: { + $ref: "#/$defs/Corporation", + }, + }, + image: { + type: "string", + format: "uri", + }, + }, + }, + Workplace: { + type: "object", + properties: { + location: { + $ref: "#/$defs/Location", + }, + fromDate: { + type: "integer", + }, + toDate: { + type: "integer", + }, + }, + }, + Location: { + type: "object", + properties: { + title: { + type: "string", + maxLength: 200, + }, + titleVariants: { + type: "string", + maxLength: 600, + }, + description: { + type: "string", + }, + image: { + type: "string", + format: "uri", + }, + parent: { + title: "Übergeordneter Ort", + $ref: "#/$defs/Location", + }, + }, + }, + PersonRole: { + type: "object", + properties: { + title: { + type: "string", + maxLength: 200, + }, + description: { + type: "string", + }, + }, + }, + CorporationRole: { + type: "object", + properties: { + title: { + type: "string", + maxLength: 200, + }, + description: { + type: "string", + }, + }, + }, + Place: { + type: "object", + properties: { + title: { + type: "string", + maxLength: 200, + }, + description: { + type: "string", + }, + titleVariants: { + type: "string", + maxLength: 600, + }, + location: { + $ref: "#/$defs/Location", + }, + parent: { + title: "Übergeordnete Stätte", + $ref: "#/$defs/Place", + }, + image: { + type: "string", + format: "uri", + }, + }, + }, + EventType: { + type: "object", + properties: { + title: { + type: "string", + maxLength: 200, + }, + description: { + type: "string", + }, + }, + }, + Corporation: { + type: "object", + properties: { + name: { + type: "string", + maxLength: 200, + }, + description: { + type: "string", + }, + nameVariant: { + type: "array", + items: { + type: "string", + }, + }, + parent: { + title: "Übergeordnete Organisation", + $ref: "#/$defs/Corporation", + }, + location: { + $ref: "#/$defs/Location", + }, + image: { + type: "string", + format: "uri", + }, + }, + }, + ResourceType: { + type: "object", + properties: { + title: { + type: "string", + maxLength: 200, + }, + description: { + type: "string", + }, + }, + }, + Resource: { + type: "object", + properties: { + title: { + type: "string", + maxLength: 200, + }, + description: { + type: "string", + }, + ppn: { + type: "string", + maxLength: 15, + }, + doi: { + type: "string", + }, + url: { + type: "string", + format: "uri", + }, + ressourceType: { + $ref: "#/$defs/ResourceType", + }, + signature: { + type: "string", + maxLength: 200, + }, + image: { + type: "string", + format: "uri", + }, + }, + }, + ExponatsAndPersons: { + type: "object", + properties: { + person: { + $ref: "#/$defs/Person", + }, + role: { + $ref: "#/$defs/PersonRole", + }, + }, + }, + ExponatsAndCorporations: { + type: "object", + properties: { + corporation: { + $ref: "#/$defs/Corporation", + }, + role: { + $ref: "#/$defs/CorporationRole", + }, + }, + }, + ExhibitionExponat: { + type: "object", + properties: { + title: { + type: "string", + maxLength: 500, + }, + titleVariants: { + type: "string", + maxLength: 600, + }, + description: { + type: "string", + }, + externalId: { + type: "string", + maxLength: 200, + }, + startDate: { + type: "object", + properties: { + dateValue: { + type: "integer", + title: "Datumswert", + maxLength: 8, + }, + dateModifier: { + type: "integer", + title: "Art der Zeitangabe", + oneOf: [ + { + const: 0, + title: "exakt", + }, + { + const: 1, + title: "ca.", + }, + { + const: 2, + title: "vor", + }, + { + const: 3, + title: "nach", + }, + ], + }, + }, + }, + endDate: { + type: "object", + properties: { + dateValue: { + type: "integer", + title: "Datumswert", + maxLength: 8, + }, + dateModifier: { + type: "integer", + title: "Art der Zeitangabe", + oneOf: [ + { + const: 0, + title: "exakt", + }, + { + const: 1, + title: "ca.", + }, + { + const: 2, + title: "vor", + }, + { + const: 3, + title: "nach", + }, + ], + }, + }, + }, + url: { + type: "string", + format: "uri", + }, + signature: { + type: "string", + maxLength: 200, + }, + exponatGenres: { + type: "array", + items: { + $ref: "#/$defs/Genre", + }, + }, + relatedPersons: { + type: "array", + items: { + $ref: "#/$defs/ExponatsAndPersons", + }, + }, + relatedCorporations: { + type: "array", + items: { + $ref: "#/$defs/ExponatsAndCorporations", + }, + }, + resources: { + type: "array", + items: { + $ref: "#/$defs/Resource", + }, + }, + }, + }, + ExhibitionCategory: { + type: "object", + properties: { + name: { + type: "string", + maxLength: 200, + }, + description: { + type: "string", + }, + }, + }, + InvolvedPerson: { + type: "object", + properties: { + person: { + $ref: "#/$defs/Person", + }, + role: { + $ref: "#/$defs/PersonRole", + }, + }, + required: ["person", "role"], + }, + InvolvedCorporation: { + type: "object", + properties: { + corporation: { + $ref: "#/$defs/Corporation", + }, + role: { + $ref: "#/$defs/CorporationRole", + }, + }, + required: ["corporation", "role"], + }, + Genre: { + type: "object", + properties: { + title: { + type: "string", + maxLength: 200, + }, + description: { + type: "string", + }, + image: { + type: "string", + format: "uri", + }, + }, + }, + Exhibition: { + type: "object", + properties: { + title: { + type: "string", + maxLength: 200, + }, + description: { + type: "string", + }, + startDate: { + type: "object", + properties: { + dateValue: { + type: "integer", + title: "Datumswert", + maxLength: 8, + }, + dateModifier: { + type: "integer", + title: "Art der Zeitangabe", + oneOf: [ + { + const: 0, + title: "exakt", + }, + { + const: 1, + title: "ca.", + }, + { + const: 2, + title: "vor", + }, + { + const: 3, + title: "nach", + }, + ], + }, + }, + }, + endDate: { + type: "object", + properties: { + dateValue: { + title: "Datumswert", + type: "integer", + maxLength: 8, + }, + dateModifier: { + type: "integer", + title: "Art der Zeitangabe", + oneOf: [ + { + const: 0, + title: "exakt", + }, + { + const: 1, + title: "ca.", + }, + { + const: 2, + title: "vor", + }, + { + const: 3, + title: "nach", + }, + ], + }, + }, + }, + subtitle: { + type: "string", + maxLength: 200, + }, + originalTitle: { + type: "string", + maxLength: 200, + }, + exhibitionSeries: { + $ref: "#/$defs/ExhibitionSeries", + }, + exhibitionCategory: { + $ref: "#/$defs/ExhibitionCategory", + }, + exhibitionGenre: { + type: "array", + items: { + $ref: "#/$defs/Genre", + }, + }, + parent: { + title: "Übergeordnete Ausstellung", + $ref: "#/$defs/Exhibition", + }, + externalId: { + type: "string", + maxLength: 50, + }, + exhibitionType: { + $ref: "#/$defs/EventType", + }, + published: { + type: "boolean", + }, + editorNote: { + type: "string", + maxLength: 300, + }, + placesUnknown: { + type: "boolean", + }, + places: { + type: "array", + items: { + $ref: "#/$defs/Place", + }, + }, + locations: { + type: "array", + items: { + $ref: "#/$defs/Location", + }, + }, + tags: { + type: "array", + items: { + $ref: "#/$defs/Tag", + }, + }, + exposedArtists: { + type: "array", + items: { + $ref: "#/$defs/Person", + }, + }, + curators: { + type: "array", + items: { + $ref: "#/$defs/Person", + }, + }, + involvedPersons: { + type: "array", + items: { + $ref: "#/$defs/InvolvedPerson", + }, + }, + organizers: { + type: "array", + items: { + $ref: "#/$defs/Corporation", + }, + }, + involvedCorporations: { + type: "array", + items: { + $ref: "#/$defs/InvolvedCorporation", + }, + }, + exhibitionweblink: { + type: "string", + format: "uri", + }, + finissage: { + type: "object", + properties: { + dateValue: { + type: "integer", + title: "Datumswert", + maxLength: 8, + }, + }, + }, + midissage: { + type: "object", + properties: { + dateValue: { + type: "integer", + title: "Datumswert", + maxLength: 8, + }, + }, + }, + vernissage: { + type: "object", + properties: { + dateValue: { + type: "integer", + title: "Datumswert", + maxLength: 8, + }, + }, + }, + exponats: { + type: "array", + items: { + $ref: "#/$defs/ExhibitionExponat", + }, + }, + catalogs: { + type: "array", + items: { + $ref: "#/$defs/Resource", + }, + }, + resources: { + type: "array", + items: { + $ref: "#/$defs/Resource", + }, + }, + image: { + type: "string", + format: "uri", + }, + }, + }, + }, +}; + +export const schema = extendDefinitionsWithProperties( + rawSchema, + () => schemaExpander.additionalProperties, + undefined, + schemaExpander.options, +); diff --git a/manifestation/exhibition/src/seed/seed.ttl b/manifestation/exhibition/src/seed/seed.ttl new file mode 100644 index 00000000..ca273930 --- /dev/null +++ b/manifestation/exhibition/src/seed/seed.ttl @@ -0,0 +1,93 @@ + @prefix slent: . + @prefix sladb: . + @prefix rdf: . + + slent:retrospective rdf:type sladb:EventType ; + sladb:title "Retrospektive" ; + sladb:description "Eine Ausstellung, die Werke aus einem längeren Zeitraum eines Künstlers oder einer Thematik zeigt." . + slent:soloExhibition rdf:type sladb:EventType ; + sladb:title "Einzelausstellung" ; + sladb:description "Eine Ausstellung gewidmet einem einzigen Künstler." . + slent:groupExhibition rdf:type sladb:EventType ; + sladb:title "Gruppenausstellung" ; + sladb:description "Eine Ausstellung, die Werke von mehreren Künstlern umfasst." . + slent:thematicExhibition rdf:type sladb:EventType ; + sladb:title "Themenausstellung" ; + sladb:description "Eine Ausstellung basierend auf einem spezifischen Thema oder Konzept." . + slent:surveyExhibition rdf:type sladb:EventType ; + sladb:title "Übersichtsausstellung" ; + sladb:description "Eine umfassende Ausstellung, die einen breiten Überblick bietet." . + + slent:specialExhibition rdf:type sladb:ExhibitionCategory ; + sladb:name "Sonderausstellung" ; + sladb:description "Eine zeitlich begrenzte, oft thematisch spezialisierte Ausstellung." . + slent:permanentExhibition rdf:type sladb:ExhibitionCategory ; + sladb:name "Dauerausstellung" ; + sladb:description "Eine langfristig angelegte Ausstellung eines Museums oder einer ähnlichen Einrichtung." . + slent:travelingExhibition rdf:type sladb:ExhibitionCategory ; + sladb:name "Wanderausstellung" ; + sladb:description "Eine Ausstellung, die an verschiedenen Orten gezeigt wird." . + slent:accrochage rdf:type sladb:ExhibitionCategory ; + sladb:name "Accrochage" ; + sladb:description "Eine kleinere, oft spontane Ausstellung von Werken, die häufig wechselt." . + slent:cabinetExhibition rdf:type sladb:ExhibitionCategory ; + sladb:name "Kabinettausstellung" ; + sladb:description "Eine kleinformatige, intime Ausstellung." . + + slent:exhibitionSeries rdf:type sladb:SeriesType ; + sladb:title "Ausstellungsreihe" ; + sladb:description "Eine Serie von Ausstellungen unter einem gemeinsamen organisatorischen Rahmen." . + slent:artFair rdf:type sladb:SeriesType ; + sladb:title "Kunstmesse" ; + sladb:description "Eine kommerzielle Veranstaltung, auf der Galerien Werke zum Verkauf anbieten." . + slent:artFestival rdf:type sladb:SeriesType ; + sladb:title "Kunstfestival" ; + sladb:description "Ein Festival, das sich auf visuelle Kunst in verschiedenen Formaten konzentriert." . + + slent:exhibitionCatalog rdf:type sladb:ResourceType ; + sladb:title "Ausstellungskatalog" ; + sladb:description "Ein publiziertes Werk, das Details und Werke einer Ausstellung dokumentiert." . + slent:review rdf:type sladb:ResourceType ; + sladb:title "Rezension" ; + sladb:description "Eine kritische Bewertung einer Ausstellung, oft publiziert in Medien." . + slent:flyer rdf:type sladb:ResourceType ; + sladb:title "Flyer" ; + sladb:description "Ein Werbemittel, das Informationen zu einer Ausstellung enthält." . + slent:poster rdf:type sladb:ResourceType ; + sladb:title "Plakat" ; + sladb:description "Ein großformatiges gedrucktes Werbemittel für eine Ausstellung." . + + slent:curator rdf:type sladb:PersonRole ; + sladb:title "Kurator:in" ; + sladb:description "Eine Person, die die Inhalte und die Organisation einer Ausstellung verantwortet." . + slent:exhibitedArtist rdf:type sladb:PersonRole ; + sladb:title "ausgestellte:r Künstler:in" ; + sladb:description "Ein Künstler, dessen Werke in einer Ausstellung gezeigt werden." . + slent:exhibitionDesigner rdf:type sladb:PersonRole ; + sladb:title "Ausstellungsdesigner:in" ; + sladb:description "Eine Person, die für das räumliche und grafische Design einer Ausstellung verantwortlich ist." . + slent:patronage rdf:type sladb:PersonRole ; + sladb:title "Schirmherr:in" ; + sladb:description "Eine Person oder Institution, die eine Ausstellung finanziell oder ideell unterstützt." . + slent:galerist rdf:type sladb:PersonRole ; + sladb:title "Galerist:in" ; + sladb:description "Ein kommerzieller Akteur, der Kunstwerke ausstellt und verkauft." . + slent:artHistorian rdf:type sladb:PersonRole ; + sladb:title "Kunsthistoriker:in" ; + sladb:description "Eine Person, die sich wissenschaftlich mit Kunst und ihrer Geschichte befasst." . + slent:collector rdf:type sladb:PersonRole ; + sladb:title "Sammler:in" ; + sladb:description "Eine Person, die Kunstwerke sammelt." . + + slent:organizer rdf:type sladb:CorporationRole ; + sladb:title "Veranstalter" ; + sladb:description "Die Institution oder Person, die eine Ausstellung oder ein Event organisiert." . + slent:lender rdf:type sladb:CorporationRole ; + sladb:title "Leihgeber" ; + sladb:description "Eine Person oder Institution, die Werke für eine Ausstellung zur Verfügung stellt." . + slent:cooperationPartner rdf:type sladb:CorporationRole ; + sladb:title "Kooperationspartner" ; + sladb:description "Eine Institution, die mit dem Hauptveranstalter zusammenarbeitet." . + slent:sponsor rdf:type sladb:CorporationRole ; + sladb:title "Sponsor" ; + sladb:description "Eine Person oder Firma, die eine Ausstellung finanziell unterstützt." . diff --git a/manifestation/exhibition/tsconfig.json b/manifestation/exhibition/tsconfig.json new file mode 100644 index 00000000..1d395447 --- /dev/null +++ b/manifestation/exhibition/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "@slub/edb-tsconfig/base.json", + "include": ["./src"], + "exclude": ["dist", "build", "node_modules"], + "compilerOptions": { + "resolveJsonModule": true + } +} diff --git a/manifestation/exhibition/tsup.config.js b/manifestation/exhibition/tsup.config.js new file mode 100644 index 00000000..85b8dcc3 --- /dev/null +++ b/manifestation/exhibition/tsup.config.js @@ -0,0 +1,5 @@ +import { makeConfigWithExternals } from "@slub/edb-tsup-config/tsup.config.js"; +import pkg from "./package.json"; + +const config = makeConfigWithExternals(pkg); +export default config; diff --git a/manifestation/kulinarik/package.json b/manifestation/kulinarik/package.json new file mode 100644 index 00000000..383ff6cd --- /dev/null +++ b/manifestation/kulinarik/package.json @@ -0,0 +1,38 @@ +{ + "name": "@slub/kulinarik-schema", + "version": "1.0.0", + "description": "Schema for the kulinarik database", + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.js", + "require": "./dist/index.cjs", + "default": "./dist/index.js", + "types": "./dist/index.d.ts" + } + }, + "scripts": { + "build": "tsup", + "dev": "tsup --watch", + "schema:export": "bun ./schemas/exportSchema.ts > ./schemas/jsonschema/Kulinarik.schema.json", + "build:prisma": "bun ./src/createPrismaSchemal.ts > ../../prisma/kulinarik.prisma", + "build:doc": "mkdir -p docs/reference && jsonschema2md -o docs/reference -d schemas/jsonschema", + "build:typebox": "mkdir -p typebox && schema2typebox --input schemas/jsonschema/Kulinarik.schema.json --output typebox/generated-typebox.ts" + }, + "devDependencies": { + "@types/rdfjs__namespace": "^2.0.8", + "@slub/json-schema-prisma-utils": "workspace:*", + "@slub/edb-build-helper": "workspace:*", + "@slub/edb-data-mapping": "workspace:*", + "@slub/edb-core-types": "workspace:*", + "json-schema": "^0.4.0", + "@adobe/jsonschema2md": "^7.1.5", + "schema2typebox": "^1.7.5" + }, + "dependencies": { + "@rdfjs/namespace": "^2.0.0" + } +} diff --git a/manifestation/kulinarik/src/createPrismaSchemal.ts b/manifestation/kulinarik/src/createPrismaSchemal.ts new file mode 100644 index 00000000..90975b85 --- /dev/null +++ b/manifestation/kulinarik/src/createPrismaSchemal.ts @@ -0,0 +1,7 @@ +import { logPrismaSchemaWithPreamble } from "@slub/json-schema-prisma-utils"; +import { extendSchemaShortcut } from "@slub/json-schema-utils"; +import { schema, schemaName } from "./schema"; + +const extendedSchema = extendSchemaShortcut(schema); + +console.log(logPrismaSchemaWithPreamble(schemaName, extendedSchema)); diff --git a/manifestation/kulinarik/src/index.ts b/manifestation/kulinarik/src/index.ts new file mode 100644 index 00000000..949eb5c5 --- /dev/null +++ b/manifestation/kulinarik/src/index.ts @@ -0,0 +1,3 @@ +export * from "./schema"; +export * from "./primaryFields"; +export * from "./makeStubSchema"; diff --git a/manifestation/kulinarik/src/makeStubSchema.ts b/manifestation/kulinarik/src/makeStubSchema.ts new file mode 100644 index 00000000..14d7a05b --- /dev/null +++ b/manifestation/kulinarik/src/makeStubSchema.ts @@ -0,0 +1,63 @@ +import { JSONSchema7 } from "json-schema"; +import { + GeneratePropertiesFunction, + prepareStubbedSchema, + SchemaExpander, +} from "@slub/json-schema-utils"; + +export const schemaExpander: SchemaExpander = { + additionalProperties: { + idAuthority: { + title: "Normdatenbeziehung", + type: "object", + properties: { + authority: { + title: "Autorität", + type: "string", + format: "uri", + }, + id: { + title: "IRI", + type: "string", + format: "uri", + }, + }, + }, + }, + options: { + excludeType: [], + excludeSemanticPropertiesForType: ["AuthorityEntry"], + }, +}; +const makeGenSlubJSONLDSemanticProperties: ( + baseIRI: string, + entitytBaseIRI: string, +) => GeneratePropertiesFunction = + (baseIRI: string, entityBaseIRI: string) => (modelName: string) => ({ + "@type": { + const: `${baseIRI}${modelName.replace(/Stub$/, "")}`, + type: "string", + }, + "@id": { + title: entityBaseIRI, + type: "string", + }, + }); + +const genSlubJSONLDSemanticProperties = makeGenSlubJSONLDSemanticProperties( + "http://ontologies.slub-dresden.de/kulinarik#", + "http://ontologies.slub-dresden.de/kulinarik/entity/", +); +const genSlubRequiredProperties = (_modelName: string) => { + return ["@type", "@id"]; +}; +export const makeStubSchema: (schema: JSONSchema7) => JSONSchema7 = ( + schema, +) => { + return prepareStubbedSchema( + schema, + genSlubJSONLDSemanticProperties, + genSlubRequiredProperties, + schemaExpander.options, + ); +}; diff --git a/manifestation/kulinarik/src/primaryFields.ts b/manifestation/kulinarik/src/primaryFields.ts new file mode 100644 index 00000000..22235539 --- /dev/null +++ b/manifestation/kulinarik/src/primaryFields.ts @@ -0,0 +1,32 @@ +import { + PrimaryField, + PrimaryFieldDeclaration, + PrimaryFieldExtractDeclaration, +} from "@slub/edb-core-types"; + +type KulinarikPrimaryFieldDeclaration = PrimaryFieldDeclaration; + +type KulinarikPrimaryFieldExtractDeclaration = PrimaryFieldExtractDeclaration< + any, + string +>; + +const defaultMapping: PrimaryField = { + label: "title", + description: "description", +}; + +const defaultMappingWithImg: PrimaryField = { + label: "title", + description: "description", + image: "image", +}; + +export const primaryFields: Partial = { + Kulinarik: defaultMappingWithImg, +}; + +export const primaryFieldExtracts: Partial = + { + ...primaryFields, + }; diff --git a/manifestation/kulinarik/src/schema.ts b/manifestation/kulinarik/src/schema.ts new file mode 100644 index 00000000..38dcc319 --- /dev/null +++ b/manifestation/kulinarik/src/schema.ts @@ -0,0 +1,67 @@ +import { JSONSchema7 } from "json-schema"; +import { extendDefinitionsWithProperties } from "@slub/json-schema-utils"; +import { schemaExpander } from "./makeStubSchema"; + +export const schemaName = "kulinarik"; + +const rawSchema: JSONSchema7 = { + $schema: "http://json-schema.org/draft-07/schema#", + $id: "https://schema.adb.arthistoricum.net/kulinarik#v1", + title: "SLUB kulinarik Datenbank", + $defs: { + Person: { + type: "object", + properties: { + name: { + type: "string", + maxLength: 200, + }, + birthDate: { + type: "string", + format: "date", + }, + deathDate: { + type: "string", + format: "date", + }, + description: { + type: "string", + }, + image: { + type: "string", + format: "uri", + }, + sameAs: { + type: "string", + format: "uri", + }, + }, + }, + Kulinarik: { + type: "object", + properties: { + title: { + type: "string", + maxLength: 200, + }, + description: { + type: "string", + }, + image: { + type: "string", + format: "uri", + }, + authoredBy: { + $ref: "#/$defs/Person", + }, + }, + }, + }, +}; + +export const schema = extendDefinitionsWithProperties( + rawSchema, + () => schemaExpander.additionalProperties, + undefined, + schemaExpander.options, +); diff --git a/manifestation/kulinarik/tsconfig.json b/manifestation/kulinarik/tsconfig.json new file mode 100644 index 00000000..1d395447 --- /dev/null +++ b/manifestation/kulinarik/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "@slub/edb-tsconfig/base.json", + "include": ["./src"], + "exclude": ["dist", "build", "node_modules"], + "compilerOptions": { + "resolveJsonModule": true + } +} diff --git a/manifestation/kulinarik/tsup.config.js b/manifestation/kulinarik/tsup.config.js new file mode 100644 index 00000000..85b8dcc3 --- /dev/null +++ b/manifestation/kulinarik/tsup.config.js @@ -0,0 +1,5 @@ +import { makeConfigWithExternals } from "@slub/edb-tsup-config/tsup.config.js"; +import pkg from "./package.json"; + +const config = makeConfigWithExternals(pkg); +export default config; diff --git a/package.json b/package.json index 191fcfc4..84d109db 100644 --- a/package.json +++ b/package.json @@ -25,10 +25,16 @@ "license": "MIT", "private": true, "scripts": { + "start": "turbo run demo", "build": "turbo run build", - "build:packages": "turbo run build --filter=@slub/*", + "build:packages": "turbo run build --filter=@slub/* --filter=@slub/edb-kxp-components --continue", + "build:manifestations": "turbo run build --filter='./manifestation/*' --continue", "build:pages": "turbo run build:pages", + "cli": "bun ./apps/edb-cli/src/index.ts", "dev": "turbo run dev --parallel", + "dev:api": "turbo run dev:api", + "dev:exhibition": "turbo run dev --parallel --filter='./apps/exhibition-live'", + "dev:vite": "turbo run dev:vite --parallel --filter='./apps/exhibition-live'", "dev:packages": "turbo run dev --parallel --filter='./packages/*'", "test": "turbo run test", "lint": "turbo run lint", @@ -37,15 +43,23 @@ "precommit": "bun run lint-staged", "prepare": "husky install", "changeset:init": "changeset init", - "changeset": "changeset" + "changeset": "changeset", + "helper:deps": "bun ./packages/build-helper/get-dependencies.js", + "build:prisma": "turbo run build:prisma && sed -i \"s/env(\\\"DATABASE_PROVIDER\\\")/\\\"${DATABASE_PROVIDER:-sqlite}\\\"/g\" ./prisma/*.prisma", + "prisma:exhibition:generate": "prisma generate --schema ./prisma/exhibition.prisma", + "prisma:exhibition:migrate": "prisma migrate dev --schema ./prisma/exhibition.prisma", + "purge": "rm -rf node_modules && find -maxdepth 3 -name node_modules | xargs rm -rf" }, "workspaces": [ - "apps/*", "packages/*", - "manifestation/*" + "packages/ideas/*", + "packages/form-renderer/*", + "manifestation/*", + "apps/*" ], "devDependencies": { "@turbo/gen": "^1.13.0", + "hygen": "^6.2.11", "eslint": "^8.57.0", "husky": "^8.0.0", "lint-staged": "^15.2.2", @@ -53,7 +67,8 @@ "tsup": "^8.0.2", "turbo": "^1.13.0", "@changesets/cli": "^2.27.1", - "typescript": "^5" + "typescript": "^5", + "prisma": "^5.17.0" }, "overrides": { "@typescript-eslint/typescript-estree": "^7.4.0" diff --git a/packages/advanced-components/package.json b/packages/advanced-components/package.json new file mode 100644 index 00000000..938b11b3 --- /dev/null +++ b/packages/advanced-components/package.json @@ -0,0 +1,38 @@ +{ + "name": "@slub/edb-advanced-components", + "version": "1.0.0", + "private": true, + "main": "src/index.tsx", + "types": "src/index.tsx", + "sideEffects": false, + "scripts": { + "typecheck": "tsc -b", + "lint": "eslint \"**/*.ts*\"", + "lint-fix": "eslint --fix \"**/*.ts*\"" + }, + "peerDependencies": { + "@mui/material": "^5", + "@mui/icons-material": "^5", + "react": "^18" + }, + "dependencies": { + "@slub/edb-state-hooks": "workspace:*", + "@slub/edb-ui-utils": "workspace:*", + "@slub/edb-core-types": "workspace:*", + "@slub/edb-global-types": "workspace:*", + "@slub/edb-basic-components": "workspace:*", + "@slub/edb-authorities": "workspace:*", + "@slub/edb-data-mapping": "workspace:*", + "@ebay/nice-modal-react": "^1.2", + "react-json-view-lite": "^1.4", + "next-i18next": "^15", + "lodash-es": "^4.17.21", + "mui-image": "^1.0.7" + }, + "devDependencies": { + "@types/react": "^18.3.3", + "@types/lodash-es": "^4.17.12", + "@types/mui-image": "^1.0.5" + } +} + diff --git a/apps/exhibition-live/components/form/DebouncedAutoComplete.tsx b/packages/advanced-components/src/form/DebouncedAutoComplete.tsx similarity index 95% rename from apps/exhibition-live/components/form/DebouncedAutoComplete.tsx rename to packages/advanced-components/src/form/DebouncedAutoComplete.tsx index 8492aba8..a16755ab 100644 --- a/apps/exhibition-live/components/form/DebouncedAutoComplete.tsx +++ b/packages/advanced-components/src/form/DebouncedAutoComplete.tsx @@ -1,23 +1,18 @@ import { Link, Search } from "@mui/icons-material"; import { CircularProgress } from "@mui/material"; import Autocomplete, { AutocompleteProps } from "@mui/material/Autocomplete"; -import { debounce } from "lodash"; +import debounce from "lodash-es/debounce"; import React, { FunctionComponent, useCallback, useEffect, - useMemo, useState, } from "react"; import { TextField } from "./TextField"; -import { useQuery } from "@tanstack/react-query"; +import { useQuery } from "@slub/edb-state-hooks"; import { useTranslation } from "next-i18next"; - -export type AutocompleteSuggestion = { - label: string; - value: string | null; -}; +import { AutocompleteSuggestion } from "@slub/edb-core-types"; export type DebouncedAutocompleteProps = { load: (value?: string) => Promise; @@ -127,7 +122,6 @@ export const DebouncedAutocomplete: FunctionComponent< ): void => { const value = e.target.value; + if (value === null) { + onChange && onChange(e as React.SyntheticEvent, null); + return; + } const selected = suggestions?.find( (suggestion) => suggestion.value === value, ); @@ -57,6 +67,8 @@ export const PreloadedOptionSelect: FunctionComponent< ); const selectID = useId(); + const { t } = useTranslation(); + const v = useMemo(() => value?.value ?? null, [value]); return ( <> @@ -64,16 +76,29 @@ export const PreloadedOptionSelect: FunctionComponent< {title} ); diff --git a/apps/exhibition-live/components/form/TextField.tsx b/packages/advanced-components/src/form/TextField.tsx similarity index 100% rename from apps/exhibition-live/components/form/TextField.tsx rename to packages/advanced-components/src/form/TextField.tsx diff --git a/packages/advanced-components/src/form/index.ts b/packages/advanced-components/src/form/index.ts new file mode 100644 index 00000000..f0baf8e1 --- /dev/null +++ b/packages/advanced-components/src/form/index.ts @@ -0,0 +1,2 @@ +export * from "./DebouncedAutoComplete"; +export * from "./PreloadedOptionSelect"; diff --git a/packages/advanced-components/src/index.tsx b/packages/advanced-components/src/index.tsx new file mode 100644 index 00000000..44a5d030 --- /dev/null +++ b/packages/advanced-components/src/index.tsx @@ -0,0 +1,7 @@ +export * from "./show"; +export * from "./table"; +export * from "./wikidata"; +export * from "./form"; +export * from "./search"; +export * from "./menu"; +export * from "./list"; diff --git a/apps/exhibition-live/components/content/list/TypedListItem.tsx b/packages/advanced-components/src/list/TypedListItem.tsx similarity index 59% rename from apps/exhibition-live/components/content/list/TypedListItem.tsx rename to packages/advanced-components/src/list/TypedListItem.tsx index c320212d..5ad3d1a3 100644 --- a/apps/exhibition-live/components/content/list/TypedListItem.tsx +++ b/packages/advanced-components/src/list/TypedListItem.tsx @@ -1,13 +1,5 @@ import React, { FunctionComponent, useCallback, useMemo } from "react"; -import { - primaryFieldExtracts, - primaryFields, - typeIRItoTypeName, -} from "../../config"; -import { - applyToEachField, - extractFieldIfString, -} from "../../utils/mapping/simpleFieldExtractor"; +import { applyToEachField, extractFieldIfString } from "@slub/edb-data-mapping"; import { Avatar, ListItem, @@ -16,43 +8,54 @@ import { ListItemText, } from "@mui/material"; import NiceModal from "@ebay/nice-modal-react"; -import { EntityDetailModal } from "../../form/show/EntityDetailModal"; -import { useRootFormContext } from "../../provider"; +import { useAdbContext } from "@slub/edb-state-hooks"; +import { EntityDetailModal } from "../show"; interface OwnProps { index: number; data: any; disableLoad?: boolean; + readonly?: boolean; } type Props = OwnProps; -const TypedListItem: FunctionComponent = ({ +export const TypedListItem: FunctionComponent = ({ index, data, disableLoad, + readonly, }) => { + const { + typeIRIToTypeName, + queryBuildOptions: { primaryFieldExtracts }, + } = useAdbContext(); const typeIRI = data["@type"] as string; const entityIRI = data["@id"] as string; - const typeName = typeIRItoTypeName(typeIRI); - //const loadedSchema = useExtendedSchema({ typeName, classIRI: typeIRI }); - const primaryFieldDesc = primaryFieldExtracts[typeName]; + const typeName = useMemo( + () => typeIRIToTypeName(typeIRI), + [typeIRI, typeIRIToTypeName], + ); + const primaryFieldDesc = useMemo( + () => primaryFieldExtracts[typeName], + [primaryFieldExtracts, typeName], + ); const { label, description, image } = useMemo( () => applyToEachField(data, primaryFieldDesc, extractFieldIfString), [data, primaryFieldDesc], ); - const { isWithinRootForm } = useRootFormContext(); const showDetailModal = useCallback(() => { NiceModal.show(EntityDetailModal, { typeIRI, entityIRI, data, disableLoad, - inlineEditing: isWithinRootForm, + disableInlineEditing: true, + readonly, }); - }, [typeIRI, entityIRI, data, disableLoad, isWithinRootForm]); + }, [typeIRI, entityIRI, data, disableLoad, EntityDetailModal]); return ( @@ -67,5 +70,3 @@ const TypedListItem: FunctionComponent = ({ ); }; - -export default TypedListItem; diff --git a/packages/advanced-components/src/list/index.ts b/packages/advanced-components/src/list/index.ts new file mode 100644 index 00000000..131a9749 --- /dev/null +++ b/packages/advanced-components/src/list/index.ts @@ -0,0 +1 @@ +export * from "./TypedListItem"; diff --git a/apps/exhibition-live/components/layout/main-layout/menu/NavCollapse.tsx b/packages/advanced-components/src/menu/NavCollapse.tsx similarity index 93% rename from apps/exhibition-live/components/layout/main-layout/menu/NavCollapse.tsx rename to packages/advanced-components/src/menu/NavCollapse.tsx index ecb14e31..c9faf665 100644 --- a/apps/exhibition-live/components/layout/main-layout/menu/NavCollapse.tsx +++ b/packages/advanced-components/src/menu/NavCollapse.tsx @@ -1,8 +1,8 @@ import { ArrowDownward as IconChevronDown, ArrowUpward as IconChevronUp, + FiberManualRecord as FiberManualRecordIcon, } from "@mui/icons-material"; -import FiberManualRecordIcon from "@mui/icons-material/FiberManualRecord"; import { Collapse, List, @@ -12,12 +12,11 @@ import { Typography, } from "@mui/material"; import { useTheme } from "@mui/material/styles"; -import { useRouter } from "next/router"; import { useEffect, useState } from "react"; -import { useThemeSettings } from "../../../state"; import { NavItem } from "./NavItem"; import { MenuCollapse } from "./types"; +import { useModifiedRouter } from "@slub/edb-state-hooks"; type NavCollapseProps = { menu: MenuCollapse; @@ -25,8 +24,7 @@ type NavCollapseProps = { }; export const NavCollapse = ({ menu, level }) => { const theme = useTheme(); - const customization = useThemeSettings(); - const { push: navigate } = useRouter(); + const { push: navigate, pathname } = useModifiedRouter(); const [open, setOpen] = useState(false); const [selected, setSelected] = useState(null); @@ -39,7 +37,6 @@ export const NavCollapse = ({ menu, level }) => { } }; - const { pathname } = useRouter(); const checkOpenForParent = (child, id) => { child.forEach((item) => { if (item.url === pathname) { diff --git a/apps/exhibition-live/components/layout/main-layout/menu/NavGroup.tsx b/packages/advanced-components/src/menu/NavGroup.tsx similarity index 97% rename from apps/exhibition-live/components/layout/main-layout/menu/NavGroup.tsx rename to packages/advanced-components/src/menu/NavGroup.tsx index 8acc0f19..32d45b0c 100644 --- a/apps/exhibition-live/components/layout/main-layout/menu/NavGroup.tsx +++ b/packages/advanced-components/src/menu/NavGroup.tsx @@ -2,7 +2,7 @@ import { Divider, List, Typography, useTheme } from "@mui/material"; import { NavCollapse } from "./NavCollapse"; import { NavItem } from "./NavItem"; -import { MenuGroup, MenuItem } from "./types"; +import { MenuGroup } from "./types"; type NavGroupProps = { item: MenuGroup; diff --git a/apps/exhibition-live/components/layout/main-layout/menu/NavItem.tsx b/packages/advanced-components/src/menu/NavItem.tsx similarity index 82% rename from apps/exhibition-live/components/layout/main-layout/menu/NavItem.tsx rename to packages/advanced-components/src/menu/NavItem.tsx index 82bacba4..3b6c7a7d 100644 --- a/apps/exhibition-live/components/layout/main-layout/menu/NavItem.tsx +++ b/packages/advanced-components/src/menu/NavItem.tsx @@ -1,4 +1,4 @@ -import AddIcon from "@mui/icons-material/Add"; +import { Add as AddIcon } from "@mui/icons-material"; import { Avatar, Chip, @@ -8,17 +8,13 @@ import { ListItemIcon, ListItemText, Typography, - useMediaQuery, } from "@mui/material"; -import { v4 as uuidv4 } from "uuid"; -import { useTheme } from "@mui/material/styles"; -import { useModifiedRouter } from "../../../basic"; +import { useTheme } from "@mui/material"; import { useEffect, useCallback } from "react"; -import { useThemeSettings } from "../../../state"; import { MenuItem } from "./types"; -import { encodeIRI } from "../../../utils/core"; -import { slent } from "../../../form/formConfigs"; +import { encodeIRI } from "@slub/edb-ui-utils"; +import { useAdbContext, useModifiedRouter } from "@slub/edb-state-hooks"; type NavItemProps = { item: MenuItem; @@ -34,16 +30,15 @@ export const NavItem = ({ }: NavItemProps) => { const theme = useTheme(); const router = useModifiedRouter(); + const { createEntityIRI } = useAdbContext(); const { pathname } = router; - const customization = useThemeSettings(); - const matchesSM = useMediaQuery(theme.breakpoints.down("lg")); const create = useCallback( (typeName: string) => { - const newEncodedURI = encodeIRI(slent(`${typeName}-${uuidv4()}`).value); + const newEncodedURI = encodeIRI(createEntityIRI(typeName)); router.push(`/create/${typeName}?encID=${newEncodedURI}`); }, - [router], + [router, createEntityIRI], ); const list = useCallback( (typeName: any) => { @@ -114,14 +109,7 @@ export const NavItem = ({ )} id === item.id) > -1 - ? "h5" - : "body1" - } - color="inherit" - > + {item.title} } @@ -174,7 +162,7 @@ export const NavItem = ({ py: level > 1 ? 1 : 1.25, justifyContent: open ? "initial" : "center", }} - selected={customization.isOpen.findIndex((id) => id === item.id) > -1} + selected={false} onClick={() => (onClick ? onClick() : itemHandler(item.id))} > {itemIcon && ( @@ -184,14 +172,7 @@ export const NavItem = ({ )} id === item.id) > -1 - ? "h5" - : "body1" - } - color="inherit" - > + {item.title} } diff --git a/packages/advanced-components/src/menu/index.tsx b/packages/advanced-components/src/menu/index.tsx new file mode 100644 index 00000000..fd612c2b --- /dev/null +++ b/packages/advanced-components/src/menu/index.tsx @@ -0,0 +1,4 @@ +export * from "./types"; +export * from "./NavItem"; +export * from "./NavCollapse"; +export * from "./NavGroup"; diff --git a/apps/exhibition-live/components/layout/main-layout/menu/types.ts b/packages/advanced-components/src/menu/types.ts similarity index 100% rename from apps/exhibition-live/components/layout/main-layout/menu/types.ts rename to packages/advanced-components/src/menu/types.ts diff --git a/apps/exhibition-live/components/form/discover/DiscoverAutocompleteInput.tsx b/packages/advanced-components/src/search/DiscoverAutocompleteInput.tsx similarity index 82% rename from apps/exhibition-live/components/form/discover/DiscoverAutocompleteInput.tsx rename to packages/advanced-components/src/search/DiscoverAutocompleteInput.tsx index ff29defa..ddcd20b9 100644 --- a/apps/exhibition-live/components/form/discover/DiscoverAutocompleteInput.tsx +++ b/packages/advanced-components/src/search/DiscoverAutocompleteInput.tsx @@ -1,16 +1,12 @@ import { TextFieldProps, useControlled } from "@mui/material"; import parse from "html-react-parser"; -import React, { FunctionComponent, useCallback, useId } from "react"; +import React, { FunctionComponent, useCallback } from "react"; -import { useGlobalCRUDOptions } from "../../state/useGlobalCRUDOptions"; -import { findEntityByClass } from "../../utils/discover"; -import { - AutocompleteSuggestion, - DebouncedAutocomplete, -} from "../DebouncedAutoComplete"; -import { loadEntityBasics } from "../../utils/crud/loadEntityBasics"; -import { defaultPrefix, sladb } from "../formConfigs"; -import { useQuery } from "@tanstack/react-query"; +import { useAdbContext, useGlobalCRUDOptions } from "@slub/edb-state-hooks"; +import { useQuery } from "@slub/edb-state-hooks"; +import { findEntityByClass, loadEntityBasics } from "@slub/sparql-schema"; +import { AutocompleteSuggestion } from "@slub/edb-core-types"; +import { DebouncedAutocomplete } from "@slub/edb-advanced-components"; interface OwnProps { selected?: AutocompleteSuggestion | null; @@ -29,11 +25,14 @@ interface OwnProps { onSearchValueChange?: (value: string | undefined) => void; searchString?: string; autocompleteDisabled?: boolean; + disabled?: boolean; } -type Props = OwnProps; +export type DiscoverAutocompleteInputProps = OwnProps; -const DiscoverAutocompleteInput: FunctionComponent = ({ +export const DiscoverAutocompleteInput: FunctionComponent< + DiscoverAutocompleteInputProps +> = ({ title = "", typeName, readonly, @@ -50,7 +49,13 @@ const DiscoverAutocompleteInput: FunctionComponent = ({ onSearchValueChange, searchString: searchStringProp, autocompleteDisabled, + disabled, }) => { + const { + typeNameToTypeIRI, + queryBuildOptions, + jsonLDConfig: { defaultPrefix }, + } = useAdbContext(); const { crudOptions } = useGlobalCRUDOptions(); const [selectedValue, setSelectedUncontrolled] = useControlled({ @@ -89,6 +94,10 @@ const DiscoverAutocompleteInput: FunctionComponent = ({ searchString || null, typeIRI, crudOptions.selectFetch, + { + defaultPrefix, + queryBuildOptions, + }, limit, ) ).map(({ name = "", value }: { name: string; value: any }) => { @@ -98,7 +107,7 @@ const DiscoverAutocompleteInput: FunctionComponent = ({ }; }) : [], - [typeIRI, crudOptions, limit], + [typeIRI, crudOptions, limit, defaultPrefix, queryBuildOptions], ); const { data: basicFields } = useQuery( @@ -106,7 +115,7 @@ const DiscoverAutocompleteInput: FunctionComponent = ({ async () => { const value = selected?.value; if (value && crudOptions && crudOptions.selectFetch) { - const typeIRI = sladb(typeName).value; + const typeIRI = typeNameToTypeIRI(typeName); return await loadEntityBasics(value, typeIRI, crudOptions.selectFetch, { defaultPrefix: defaultPrefix, }); @@ -148,6 +157,7 @@ const DiscoverAutocompleteInput: FunctionComponent = ({ return ( = ({ /> ); }; - -export default DiscoverAutocompleteInput; diff --git a/apps/exhibition-live/components/form/discover/DiscoverSearchTable.stories.tsx b/packages/advanced-components/src/search/DiscoverSearchTable.stories.tsx similarity index 66% rename from apps/exhibition-live/components/form/discover/DiscoverSearchTable.stories.tsx rename to packages/advanced-components/src/search/DiscoverSearchTable.stories.tsx index 10d380cc..575c8b3d 100644 --- a/apps/exhibition-live/components/form/discover/DiscoverSearchTable.stories.tsx +++ b/packages/advanced-components/src/search/DiscoverSearchTable.stories.tsx @@ -1,9 +1,9 @@ import React from "react"; -import DiscoverSearchTable from "./DiscoverSearchTable"; +import { DiscoverSearchTable } from "./DiscoverSearchTable"; export default { - title: "form/discover/DiscoverSearchTable", + title: "ui/form/DiscoverSearchTable", component: DiscoverSearchTable, }; diff --git a/apps/exhibition-live/components/form/discover/DiscoverSearchTable.tsx b/packages/advanced-components/src/search/DiscoverSearchTable.tsx similarity index 64% rename from apps/exhibition-live/components/form/discover/DiscoverSearchTable.tsx rename to packages/advanced-components/src/search/DiscoverSearchTable.tsx index d71496f8..658ffbd2 100644 --- a/apps/exhibition-live/components/form/discover/DiscoverSearchTable.tsx +++ b/packages/advanced-components/src/search/DiscoverSearchTable.tsx @@ -1,45 +1,51 @@ -import { List, ListItemProps } from "@mui/material"; +import { List } from "@mui/material"; import React, { FunctionComponent, useCallback, useEffect, + useMemo, useState, } from "react"; -import { useGlobalCRUDOptions } from "../../state/useGlobalCRUDOptions"; -import { findEntityByClass } from "../../utils/discover"; -import { sladb } from "../formConfigs"; -import ClassicResultListItem from "../result/ClassicResultListItem"; -import { EntityDetailElement } from "../show"; +import { useAdbContext, useGlobalCRUDOptions } from "@slub/edb-state-hooks"; +import { findEntityByClass } from "@slub/sparql-schema"; +import { ClassicResultListItem } from "@slub/edb-basic-components"; +import { EntityDetailElement } from "@slub/edb-advanced-components"; -type Props = { +export type DiscoverSearchTableProps = { searchString: string; typeName?: string; - classIRI?: string; - onSelect?: (id: string | undefined) => void; onAcceptItem?: (id: string | undefined, data: any) => void; selectedIndex?: number; }; -const DiscoverSearchTable: FunctionComponent = ({ - searchString, - typeName = "Person", - classIRI = sladb[typeName].value, - onSelect, - onAcceptItem, - selectedIndex, -}) => { +export const DiscoverSearchTable: FunctionComponent< + DiscoverSearchTableProps +> = ({ searchString, typeName = "Person", onAcceptItem, selectedIndex }) => { const [resultTable, setResultTable] = useState(); - const [selectedId, setSelectedId] = useState(); - const [selectedEntry, setSelectedEntry] = useState(); + const { + typeNameToTypeIRI, + jsonLDConfig: { defaultPrefix }, + queryBuildOptions, + } = useAdbContext(); const { crudOptions } = useGlobalCRUDOptions(); - const typeIRI = sladb[typeName].value; + const typeIRI = useMemo( + () => typeNameToTypeIRI(typeName), + [typeName, typeNameToTypeIRI], + ); const fetchData = useCallback(async () => { - if (!searchString || searchString.length < 1 || !crudOptions) return; + console.log("fetch data"); + if (!searchString || searchString.length < 1 || !crudOptions || !typeIRI) + return; setResultTable( ( - await findEntityByClass(searchString, classIRI, crudOptions.selectFetch) + await findEntityByClass( + searchString, + typeIRI, + crudOptions.selectFetch, + { defaultPrefix, queryBuildOptions }, + ) ).map(({ name = "", value }: { name: string; value: any }) => { return { label: name, @@ -47,7 +53,7 @@ const DiscoverSearchTable: FunctionComponent = ({ }; }), ); - }, [searchString, classIRI, crudOptions]); + }, [searchString, typeIRI, crudOptions, defaultPrefix, queryBuildOptions]); const handleSelect = useCallback( (id: string | undefined) => { @@ -96,5 +102,3 @@ const DiscoverSearchTable: FunctionComponent = ({ ); }; - -export default DiscoverSearchTable; diff --git a/packages/advanced-components/src/search/index.ts b/packages/advanced-components/src/search/index.ts new file mode 100644 index 00000000..910654f6 --- /dev/null +++ b/packages/advanced-components/src/search/index.ts @@ -0,0 +1,2 @@ +export * from "./DiscoverSearchTable"; +export * from "./DiscoverAutocompleteInput"; diff --git a/apps/exhibition-live/components/form/show/EntityChip.tsx b/packages/advanced-components/src/show/EntityChip.tsx similarity index 66% rename from apps/exhibition-live/components/form/show/EntityChip.tsx rename to packages/advanced-components/src/show/EntityChip.tsx index 3b2ebcc5..66db4ad9 100644 --- a/apps/exhibition-live/components/form/show/EntityChip.tsx +++ b/packages/advanced-components/src/show/EntityChip.tsx @@ -1,49 +1,50 @@ -import { useTypeIRIFromEntity } from "../../state"; +import { useAdbContext, useTypeIRIFromEntity } from "@slub/edb-state-hooks"; import React, { MouseEvent, useCallback, useMemo, useState } from "react"; -import { primaryFieldExtracts, typeIRItoTypeName } from "../../config"; -import useExtendedSchema from "../../state/useExtendedSchema"; -import { useCRUDWithQueryClient } from "../../state/useCRUDWithQueryClient"; -import { useTranslation } from "next-i18next"; -import { PrimaryFieldResults } from "../../utils/types"; import { - applyToEachField, - extractFieldIfString, -} from "../../utils/mapping/simpleFieldExtractor"; -import { ellipsis } from "../../utils/core"; + useCRUDWithQueryClient, + useExtendedSchema, +} from "@slub/edb-state-hooks"; +import { applyToEachField, extractFieldIfString } from "@slub/edb-data-mapping"; +import { ellipsis } from "@slub/edb-ui-utils"; import NiceModal from "@ebay/nice-modal-react"; -import { EntityDetailModal } from "./EntityDetailModal"; import { Avatar, Chip, ChipProps, Tooltip } from "@mui/material"; -import { useRootFormContext } from "../../provider"; +import { PrimaryFieldResults } from "@slub/edb-core-types"; -type EntityChipProps = { +export type EntityChipProps = { index?: number; entityIRI: string; typeIRI?: string; data?: any; - inlineEditing?: boolean; } & ChipProps; export const EntityChip = ({ index, entityIRI, typeIRI, data: defaultData, - inlineEditing, ...chipProps }: EntityChipProps) => { const typeIRIs = useTypeIRIFromEntity(entityIRI); const classIRI: string | undefined = typeIRI || typeIRIs?.[0]; - const typeName = useMemo(() => typeIRItoTypeName(classIRI), [classIRI]); - const loadedSchema = useExtendedSchema({ typeName, classIRI }); + const { + queryBuildOptions: { primaryFieldExtracts }, + typeIRIToTypeName, + components: { EntityDetailModal }, + } = useAdbContext(); + const typeName = useMemo( + () => typeIRIToTypeName(classIRI), + [classIRI, typeIRIToTypeName], + ); + const loadedSchema = useExtendedSchema({ typeName }); const { loadQuery: { data: rawData }, - } = useCRUDWithQueryClient( + } = useCRUDWithQueryClient({ entityIRI, - classIRI, - loadedSchema, - { enabled: true, refetchOnWindowFocus: true }, - "show", - ); - const { t } = useTranslation(); + typeIRI: classIRI, + schema: loadedSchema, + queryOptions: { enabled: true, refetchOnWindowFocus: true }, + loadQueryKey: "show", + }); + const data = rawData?.document?.["@type"] ? rawData?.document : defaultData; const cardInfo = useMemo>(() => { const fieldDecl = primaryFieldExtracts[typeName]; @@ -64,7 +65,7 @@ export const EntityChip = ({ description: null, image: null, }; - }, [typeName, data]); + }, [typeName, data, primaryFieldExtracts]); const { label, image, description } = cardInfo; //Sorry for this hack, in future we will have class dependent List items const variant = useMemo( @@ -72,18 +73,15 @@ export const EntityChip = ({ [typeIRI], ); const [tooltipEnabled, setTooltipEnabled] = useState(false); - const { isWithinRootForm } = useRootFormContext(); const showDetailModal = useCallback( (e: MouseEvent) => { e.preventDefault(); NiceModal.show(EntityDetailModal, { entityIRI, data: {}, - inlineEditing: - inlineEditing === undefined ? isWithinRootForm : inlineEditing, }); }, - [entityIRI, isWithinRootForm, inlineEditing], + [entityIRI, EntityDetailModal], ); const handleShouldShow = useCallback( (e: MouseEvent) => { diff --git a/packages/advanced-components/src/show/EntityDetailCard.tsx b/packages/advanced-components/src/show/EntityDetailCard.tsx new file mode 100644 index 00000000..75a1775b --- /dev/null +++ b/packages/advanced-components/src/show/EntityDetailCard.tsx @@ -0,0 +1,168 @@ +import React, { FunctionComponent, useCallback } from "react"; +import { JsonView } from "react-json-view-lite"; +import { + Box, + Button, + Card, + CardActionArea, + CardActions, + CardContent, + CardMedia, + IconButton, + Typography, +} from "@mui/material"; +import { useTranslation } from "next-i18next"; +import { AllPropTableProps, LobidAllPropTable } from "../table"; +import { encodeIRI } from "@slub/edb-ui-utils"; + +import NiceModal from "@ebay/nice-modal-react"; +import { + useAdbContext, + useModalRegistry, + useModifiedRouter, + useSettings, +} from "@slub/edb-state-hooks"; +import isString from "lodash-es/isString"; +import { Edit } from "@mui/icons-material"; +import { PrimaryFieldResults } from "@slub/edb-core-types"; +import { ModRouter } from "@slub/edb-global-types"; + +type OwnProps = { + typeIRI: string; + entityIRI: string; + cardInfo: PrimaryFieldResults; + cardActionChildren?: React.ReactNode; + data: any; + readonly?: boolean; + disableInlineEditing?: boolean; + onEditClicked?: () => void; + tableProps?: Partial; +}; + +export type EntityDetailCardProps = OwnProps; +export const EntityDetailCard: FunctionComponent = ({ + typeIRI, + entityIRI, + cardInfo, + data, + cardActionChildren, + readonly, + disableInlineEditing, + onEditClicked, + tableProps = {}, +}) => { + const { t } = useTranslation(); + const { + typeIRIToTypeName, + components: { EditEntityModal }, + } = useAdbContext(); + + //FIXME: This is a workaround for the missing router in the context in some circumstances, yet to be researched + let router: ModRouter | undefined; + try { + router = useModifiedRouter(); + } catch (e) {} + + const { registerModal } = useModalRegistry(NiceModal); + const editEntry = useCallback(() => { + if (!disableInlineEditing) { + const modalID = `edit-${typeIRI}-${entityIRI}`; + registerModal(modalID, EditEntityModal); + NiceModal.show(modalID, { + entityIRI: entityIRI, + typeIRI: typeIRI, + data, + disableLoad: true, + }); + } else { + const typeName = typeIRIToTypeName(typeIRI); + router && + router.push(`/create/${typeName}?encID=${encodeIRI(entityIRI)}`); + } + onEditClicked && onEditClicked(); + }, [ + typeIRI, + entityIRI, + disableInlineEditing, + typeIRIToTypeName, + registerModal, + data, + onEditClicked, + EditEntityModal, + router, + ]); + + const { + features: { enableDebug, enableStylizedCard }, + } = useSettings(); + + return ( + <> + + + {cardInfo.image && ( + + )} + + + {cardInfo.label} + + {isString(data?.originalTitle) || + isString(data?.subtitle) || + (cardInfo.description?.length < 300 && ( + + {data?.subtitle || + data?.originalTitle || + cardInfo.description} + + ))} + + + {cardActionChildren !== null && ( + + {typeof cardActionChildren !== "undefined" ? ( + cardActionChildren + ) : ( + <> + {!readonly && ( + } + > + {!disableInlineEditing ? t("edit inline") : t("edit")} + + )} + + )} + + )} + + {/* + + */} + + + + {enableDebug && ( + <> + lvl < 3} /> + lvl < 3} /> + + )} + + ); +}; diff --git a/apps/exhibition-live/components/form/show/EntityDetailElement.tsx b/packages/advanced-components/src/show/EntityDetailElement.tsx similarity index 59% rename from apps/exhibition-live/components/form/show/EntityDetailElement.tsx rename to packages/advanced-components/src/show/EntityDetailElement.tsx index 1c4a643b..009dd11c 100644 --- a/apps/exhibition-live/components/form/show/EntityDetailElement.tsx +++ b/packages/advanced-components/src/show/EntityDetailElement.tsx @@ -1,25 +1,18 @@ import { Box, BoxProps } from "@mui/material"; -import useExtendedSchema from "../../state/useExtendedSchema"; -import { useCRUDWithQueryClient } from "../../state/useCRUDWithQueryClient"; +import { useAdbContext, useCRUDWithQueryClient } from "@slub/edb-state-hooks"; import { useMemo } from "react"; -import { primaryFields, typeIRItoTypeName } from "../../config"; -import { - applyToEachField, - extractFieldIfString, -} from "../../utils/mapping/simpleFieldExtractor"; -import { PrimaryFieldResults } from "../../utils/types"; +import { applyToEachField, extractFieldIfString } from "@slub/edb-data-mapping"; import { EntityDetailCard } from "./EntityDetailCard"; -import { useTypeIRIFromEntity } from "../../state"; -import { useTranslation } from "next-i18next"; -import { PrimaryField } from "@slub/edb-core-types"; -import { filterUndefOrNull } from "@slub/edb-core-utils"; +import { useTypeIRIFromEntity, useExtendedSchema } from "@slub/edb-state-hooks"; +import { PrimaryField, PrimaryFieldResults } from "@slub/edb-core-types"; +import { filterUndefOrNull } from "@slub/edb-ui-utils"; -type EntityDetailElementProps = { +export type EntityDetailElementProps = { typeIRI: string | undefined; entityIRI: string; data: any; cardActionChildren?: React.ReactNode; - inlineEditing?: boolean; + disableInlineEditing?: boolean; readonly?: boolean; }; @@ -28,29 +21,38 @@ export const EntityDetailElement = ({ entityIRI, data: initialData, cardActionChildren, - inlineEditing, + disableInlineEditing, readonly, ...rest }: EntityDetailElementProps & Partial) => { - const boxProps = rest || {}; + const { + queryBuildOptions: { primaryFields }, + typeIRIToTypeName, + } = useAdbContext(); const typeIRIs = useTypeIRIFromEntity(entityIRI); const classIRI: string | undefined = typeIRI || typeIRIs?.[0]; - const typeName = useMemo(() => typeIRItoTypeName(classIRI), [classIRI]); - const loadedSchema = useExtendedSchema({ typeName, classIRI }); + const typeName = useMemo( + () => typeIRIToTypeName(classIRI), + [classIRI, typeIRIToTypeName], + ); + const loadedSchema = useExtendedSchema({ typeName }); const { loadQuery: { data: rawData }, - } = useCRUDWithQueryClient( + } = useCRUDWithQueryClient({ entityIRI, - classIRI, - loadedSchema, - { enabled: true, refetchOnWindowFocus: true, initialData: initialData }, - "show", - ); - const { t } = useTranslation(); + typeIRI: classIRI, + schema: loadedSchema, + queryOptions: { + enabled: true, + refetchOnWindowFocus: true, + initialData: initialData, + }, + loadQueryKey: "show", + }); const data = initialData || rawData?.document; const fieldDeclaration = useMemo( () => primaryFields[typeName] as PrimaryField, - [typeName], + [typeName, primaryFields], ); const cardInfo = useMemo>(() => { if (data && fieldDeclaration) @@ -75,7 +77,7 @@ export const EntityDetailElement = ({ data={data} cardInfo={cardInfo} cardActionChildren={cardActionChildren} - inlineEditing={inlineEditing} + disableInlineEditing={disableInlineEditing} readonly={readonly} tableProps={{ disabledProperties }} /> diff --git a/apps/exhibition-live/components/form/show/EntityDetailListItem.tsx b/packages/advanced-components/src/show/EntityDetailListItem.tsx similarity index 68% rename from apps/exhibition-live/components/form/show/EntityDetailListItem.tsx rename to packages/advanced-components/src/show/EntityDetailListItem.tsx index f14fb602..d80e9153 100644 --- a/apps/exhibition-live/components/form/show/EntityDetailListItem.tsx +++ b/packages/advanced-components/src/show/EntityDetailListItem.tsx @@ -8,23 +8,18 @@ import { Stack, } from "@mui/material"; import React, { useCallback, useMemo } from "react"; -import { useTypeIRIFromEntity } from "../../state"; -import { primaryFields, typeIRItoTypeName } from "../../config"; -import useExtendedSchema from "../../state/useExtendedSchema"; -import { useCRUDWithQueryClient } from "../../state/useCRUDWithQueryClient"; -import { useTranslation } from "next-i18next"; -import { PrimaryFieldResults } from "../../utils/types"; +import { useAdbContext, useTypeIRIFromEntity } from "@slub/edb-state-hooks"; import { - applyToEachField, - extractFieldIfString, -} from "../../utils/mapping/simpleFieldExtractor"; + useCRUDWithQueryClient, + useExtendedSchema, +} from "@slub/edb-state-hooks"; +import { applyToEachField, extractFieldIfString } from "@slub/edb-data-mapping"; import NiceModal from "@ebay/nice-modal-react"; -import { EntityDetailModal } from "./EntityDetailModal"; import { Clear, HideImage } from "@mui/icons-material"; -import { ellipsis } from "../../utils/core"; -import { useRootFormContext } from "../../provider"; +import { ellipsis } from "@slub/edb-ui-utils"; +import { PrimaryFieldResults } from "@slub/edb-core-types"; -type EntityDetailListItemProps = { +export type EntityDetailListItemProps = { entityIRI: string; typeIRI?: string; onClear?: () => void; @@ -36,20 +31,27 @@ export const EntityDetailListItem = ({ onClear, data: defaultData, }: EntityDetailListItemProps) => { + const { + queryBuildOptions: { primaryFields }, + typeIRIToTypeName, + components: { EntityDetailModal }, + } = useAdbContext(); const typeIRIs = useTypeIRIFromEntity(entityIRI); const classIRI: string | undefined = typeIRI || typeIRIs?.[0]; - const typeName = useMemo(() => typeIRItoTypeName(classIRI), [classIRI]); - const loadedSchema = useExtendedSchema({ typeName, classIRI }); + const typeName = useMemo( + () => typeIRIToTypeName(classIRI), + [classIRI, typeIRIToTypeName], + ); + const loadedSchema = useExtendedSchema({ typeName }); const { loadQuery: { data: rawData }, - } = useCRUDWithQueryClient( + } = useCRUDWithQueryClient({ entityIRI, - classIRI, - loadedSchema, - { enabled: true, refetchOnWindowFocus: true }, - "show", - ); - const { t } = useTranslation(); + typeIRI: classIRI, + schema: loadedSchema, + queryOptions: { enabled: true, refetchOnWindowFocus: true }, + loadQueryKey: "show", + }); const data = rawData?.document?.["@type"] ? rawData?.document : defaultData; const cardInfo = useMemo>(() => { const fieldDecl = primaryFields[typeName]; @@ -70,17 +72,15 @@ export const EntityDetailListItem = ({ description: null, image: null, }; - }, [typeName, data]); + }, [typeName, data, primaryFields]); const { label, image, description } = cardInfo; - const { isWithinRootForm } = useRootFormContext(); const showDetailModal = useCallback(() => { NiceModal.show(EntityDetailModal, { typeIRI, entityIRI, data, - inlineEditing: isWithinRootForm, }); - }, [typeIRI, entityIRI, data, isWithinRootForm]); + }, [typeIRI, entityIRI, data, EntityDetailModal]); //Sorry for this hack, in future we will have class dependent List items const variant = useMemo( () => (typeIRI.endsWith("Person") ? "circular" : "rounded"), diff --git a/apps/exhibition-live/components/form/show/EntityDetailModal.tsx b/packages/advanced-components/src/show/EntityDetailModal.tsx similarity index 76% rename from apps/exhibition-live/components/form/show/EntityDetailModal.tsx rename to packages/advanced-components/src/show/EntityDetailModal.tsx index 118735a1..75e0a29f 100644 --- a/apps/exhibition-live/components/form/show/EntityDetailModal.tsx +++ b/packages/advanced-components/src/show/EntityDetailModal.tsx @@ -11,29 +11,15 @@ import { Typography, } from "@mui/material"; import { Close as CloseIcon } from "@mui/icons-material"; -import useExtendedSchema from "../../state/useExtendedSchema"; -import { useCRUDWithQueryClient } from "../../state/useCRUDWithQueryClient"; +import { useAdbContext, useCRUDWithQueryClient } from "@slub/edb-state-hooks"; import { useCallback, useMemo, useState } from "react"; -import { primaryFields, typeIRItoTypeName } from "../../config"; -import { - applyToEachField, - extractFieldIfString, -} from "../../utils/mapping/simpleFieldExtractor"; -import { PrimaryFieldResults } from "../../utils/types"; +import { applyToEachField, extractFieldIfString } from "@slub/edb-data-mapping"; import { EntityDetailCard } from "./EntityDetailCard"; -import { useTypeIRIFromEntity } from "../../state"; +import { useTypeIRIFromEntity, useExtendedSchema } from "@slub/edb-state-hooks"; import { useTranslation } from "next-i18next"; import { filterUndefOrNull } from "@slub/edb-core-utils"; -import { PrimaryField } from "@slub/edb-core-types"; - -type EntityDetailModalProps = { - typeIRI: string | undefined; - entityIRI: string; - data: any; - disableLoad?: boolean; - readonly?: boolean; - inlineEditing?: boolean; -}; +import { PrimaryField, PrimaryFieldResults } from "@slub/edb-core-types"; +import { EntityDetailModalProps } from "@slub/edb-global-types"; export const EntityDetailModal = NiceModal.create( ({ @@ -42,26 +28,33 @@ export const EntityDetailModal = NiceModal.create( data: defaultData, disableLoad, readonly, - inlineEditing, + disableInlineEditing, }: EntityDetailModalProps) => { + const { + queryBuildOptions: { primaryFields }, + typeIRIToTypeName, + } = useAdbContext(); const modal = useModal(); const typeIRIs = useTypeIRIFromEntity(entityIRI); const classIRI: string | undefined = typeIRI || typeIRIs?.[0]; - const typeName = useMemo(() => typeIRItoTypeName(classIRI), [classIRI]); - const loadedSchema = useExtendedSchema({ typeName, classIRI }); + const typeName = useMemo( + () => typeIRIToTypeName(classIRI), + [classIRI, typeIRIToTypeName], + ); + const loadedSchema = useExtendedSchema({ typeName }); const { loadQuery: { data: rawData }, - } = useCRUDWithQueryClient( + } = useCRUDWithQueryClient({ entityIRI, - classIRI, - loadedSchema, - { + typeIRI: classIRI, + schema: loadedSchema, + queryOptions: { enabled: !disableLoad, refetchOnWindowFocus: true, initialData: defaultData, }, - "show", - ); + loadQueryKey: "show", + }); const { t } = useTranslation(); const data = rawData?.document || defaultData; const cardInfo = useMemo>(() => { @@ -73,7 +66,7 @@ export const EntityDetailModal = NiceModal.create( description: null, image: null, }; - }, [typeName, data]); + }, [typeName, data, primaryFields]); const [aboutToRemove, setAboutToRemove] = useState(false); const removeSlowly = useCallback(() => { @@ -84,7 +77,7 @@ export const EntityDetailModal = NiceModal.create( const fieldDeclaration = useMemo( () => primaryFields[typeName] as PrimaryField, - [typeName], + [typeName, primaryFields], ); const disabledProperties = useMemo( () => filterUndefOrNull(Object.values(fieldDeclaration || {})), @@ -127,7 +120,7 @@ export const EntityDetailModal = NiceModal.create( entityIRI={entityIRI} data={data} cardInfo={cardInfo} - inlineEditing={inlineEditing} + disableInlineEditing={disableInlineEditing} readonly={readonly} onEditClicked={removeSlowly} tableProps={{ disabledProperties }} diff --git a/apps/exhibition-live/components/form/show/index.ts b/packages/advanced-components/src/show/index.ts similarity index 100% rename from apps/exhibition-live/components/form/show/index.ts rename to packages/advanced-components/src/show/index.ts index 6444519e..2bf8b097 100644 --- a/apps/exhibition-live/components/form/show/index.ts +++ b/packages/advanced-components/src/show/index.ts @@ -1,5 +1,5 @@ +export * from "./EntityChip"; export * from "./EntityDetailCard"; -export * from "./EntityDetailModal"; -export * from "./EntityDetailListItem"; export * from "./EntityDetailElement"; -export * from "./EntityChip"; +export * from "./EntityDetailListItem"; +export * from "./EntityDetailModal"; diff --git a/apps/exhibition-live/components/form/lobid/LobidAllPropTable.tsx b/packages/advanced-components/src/table/LobidAllPropTable.tsx similarity index 68% rename from apps/exhibition-live/components/form/lobid/LobidAllPropTable.tsx rename to packages/advanced-components/src/table/LobidAllPropTable.tsx index 602f8db5..8fb80ffb 100644 --- a/apps/exhibition-live/components/form/lobid/LobidAllPropTable.tsx +++ b/packages/advanced-components/src/table/LobidAllPropTable.tsx @@ -1,4 +1,3 @@ -import { Check, MoreVert as MoreVertIcon } from "@mui/icons-material"; import { Accordion, AccordionDetails, @@ -20,24 +19,23 @@ import { Typography, } from "@mui/material"; import React, { + Fragment, FunctionComponent, useCallback, useMemo, useState, } from "react"; -import { MappingConfigurationDialog } from "../../mapping/MappingConfigurationDialog"; -import { gndBaseIRI } from "../../utils/gnd/prefixes"; -import { EntityChip } from "../show"; -import { useQuery } from "@tanstack/react-query"; -import { findEntityWithinLobidByIRI } from "../../utils/lobid/findEntityWithinLobid"; -import WikidataAllPropTable from "../wikidata/WikidataAllPropTable"; -import { OverflowContainer } from "../../lists"; -import { specialDate2LocalDate } from "../../utils/specialDate2LocalDate"; +import { camelCaseToTitleCase } from "@slub/edb-ui-utils"; +import { WikidataAllPropTable } from "../wikidata"; +import { OverflowContainer } from "@slub/edb-basic-components"; +import { specialDate2LocalDate } from "@slub/edb-ui-utils"; import { useTranslation } from "next-i18next"; -import isNil from "lodash/isNil"; -import { isValidUrl } from "@slub/edb-core-utils"; +import { isValidUrl } from "@slub/edb-ui-utils"; import { Image } from "mui-image"; +import { EntityChip } from "../show"; +import { useQuery } from "@slub/edb-state-hooks"; +import { findEntityWithinLobidByIRI, gndBaseIRI } from "@slub/edb-authorities"; export interface AllPropTableProps { allProps?: any; @@ -49,12 +47,6 @@ export interface AllPropTableProps { type Props = AllPropTableProps; -const camelCaseToTitleCase = (str: string) => { - return str.replace(/([A-Z])/g, " $1").replace(/^./, function (str) { - return str.toUpperCase(); - }); -}; - const LabledLink = ({ uri, label, @@ -67,8 +59,9 @@ const LabledLink = ({ const urlSuffix = useMemo( () => uri.substring( - (uri.includes("#") ? uri.lastIndexOf("#") : uri.lastIndexOf("/")) + 1 ?? - 0, + uri.includes("#") + ? uri.lastIndexOf("#") + : uri.lastIndexOf("/") + 1 || 0, uri.length, ), [uri], @@ -84,6 +77,46 @@ const LabledLink = ({ ); }; +type ObjectGroup = { + groupKey: string; + properties: Record; +}; + +type ObjectGroups = { + default: Record; + groups: ObjectGroup[]; +}; + +const emtyObjectGroups: ObjectGroups = { + default: {}, + groups: [], +}; + +const obj2Groups = (obj: Record): ObjectGroups => { + //each value, that is an object and has no @id is a group of properties + //filter all but objects without @id + const groups = Object.entries(obj) + .filter( + ([_, value]) => + typeof value === "object" && + !value["@id"] && + !Array.isArray(value) && + Object.keys(value).length > 0, + ) + .map(([groupKey, properties]) => ({ groupKey, properties })); + + const nonGroupedProperties = Object.fromEntries( + Object.entries(obj).filter( + ([_, value]) => + typeof value !== "object" || value["@id"] || Array.isArray(value), + ), + ); + return { + groups, + default: nonGroupedProperties, + }; +}; + const isImageUrl = (url: string) => { return url.match(/\.(jpeg|jpg|gif|png)(\?.*)?$/) != null; }; @@ -125,11 +158,6 @@ const PropertyContextMenu = ({ return ( <> - create Mapping Property info @@ -143,13 +171,11 @@ const PropertyItem = ({ value: originalValue, onEntityChange, disableContextMenu, - inlineEditing, }: { property: string; value: any; onEntityChange?: (uri: string) => void; disableContextMenu?: boolean; - inlineEditing?: boolean; }) => { const { menuAnchorEl, menuOpen, handleMenuClick, handleMenuClose } = useMenuState(); @@ -171,7 +197,7 @@ const PropertyItem = ({ > {disableContextMenu ? ( - {exists(property, { ns: "table" }) + {typeof exists === "function" && exists(property, { ns: "table" }) ? t(property) : camelCaseToTitleCase(property)} @@ -188,7 +214,9 @@ const PropertyItem = ({ aria-label={"mapping"} onClick={handleMenuClick} > - {exists(property) ? t(property) : camelCaseToTitleCase(property)} + {typeof exists === "function" && exists(property) + ? t(property) + : camelCaseToTitleCase(property)} ); } @@ -258,7 +285,13 @@ const PropertyItem = ({ ) : typeof value === "string" || typeof value === "number" ? ( property.toLowerCase().includes("date") ? ( - specialDate2LocalDate(value as number, locale) + (() => { + try { + return specialDate2LocalDate(value as number, locale); + } catch (e) { + return String(e); + } + })() ) : isValidUrl(value as string) ? ( isImageUrl(value as string) ? ( @@ -285,23 +318,34 @@ const PropertyItem = ({ ); }; -const LobidAllPropTable: FunctionComponent = ({ +export const LobidAllPropTable: FunctionComponent = ({ allProps, disableContextMenu, inlineEditing, disabledProperties, }) => { const gndIRI = useMemo(() => { - const gndIRI_ = allProps?.idAuthority?.["@id"] || allProps?.idAuthority; + const gndIRI_ = allProps?.idAuthority?.id; if (typeof gndIRI_ !== "string") return undefined; return gndIRI_.startsWith(gndBaseIRI) ? gndIRI_ : undefined; }, [allProps]); const { data: rawEntry } = useQuery( ["lobid", gndIRI], () => findEntityWithinLobidByIRI(gndIRI), + // @ts-ignore { enabled: !!gndIRI }, ); + const grouped = React.useMemo( + () => (allProps ? obj2Groups(allProps) : emtyObjectGroups), + [allProps], + ); + + const { + i18n: { exists }, + t, + } = useTranslation(); + return ( <> @@ -310,8 +354,8 @@ const LobidAllPropTable: FunctionComponent = ({ aria-label="custom detail table" > - {allProps && - Object.entries(allProps) + {grouped?.default && + Object.entries(grouped.default) .filter( ([key, value]) => disabledProperties?.includes(key) !== true && @@ -330,9 +374,45 @@ const LobidAllPropTable: FunctionComponent = ({ property={key} value={value} disableContextMenu={disableContextMenu} - inlineEditing={true} /> ))} + {grouped?.groups && + grouped.groups + .filter(({ properties }) => Object.keys(properties).length > 0) + .map(({ groupKey, properties }) => ( + + + + + {typeof exists === "function" && exists(groupKey) + ? t(groupKey) + : camelCaseToTitleCase(groupKey)} + + + + {Object.entries(properties) + .filter( + ([key, value]) => + disabledProperties?.includes(key) !== true && + !key.startsWith("@") && + (typeof value === "string" || + typeof value === "number" || + typeof value === "boolean" || + (typeof value === "object" && + value["@id"] && + value["@type"]) || + (Array.isArray(value) && value.length > 0)), + ) + .map(([key, value]) => ( + + ))} + + ))} @@ -346,7 +426,7 @@ const LobidAllPropTable: FunctionComponent = ({ - {(rawEntry.sameAs || []) + {((rawEntry as any)?.sameAs || []) .filter(({ id }) => id.startsWith("http://www.wikidata.org/entity/"), ) @@ -365,5 +445,3 @@ const LobidAllPropTable: FunctionComponent = ({ ); }; - -export default LobidAllPropTable; diff --git a/packages/advanced-components/src/table/index.ts b/packages/advanced-components/src/table/index.ts new file mode 100644 index 00000000..aec7750c --- /dev/null +++ b/packages/advanced-components/src/table/index.ts @@ -0,0 +1 @@ +export * from "./LobidAllPropTable"; diff --git a/apps/exhibition-live/components/form/wikidata/WikidataAllPropTable.tsx b/packages/advanced-components/src/wikidata/WikidataAllPropTable.tsx similarity index 90% rename from apps/exhibition-live/components/form/wikidata/WikidataAllPropTable.tsx rename to packages/advanced-components/src/wikidata/WikidataAllPropTable.tsx index ef130e41..b0de4b94 100644 --- a/apps/exhibition-live/components/form/wikidata/WikidataAllPropTable.tsx +++ b/packages/advanced-components/src/wikidata/WikidataAllPropTable.tsx @@ -12,16 +12,18 @@ import React, { FunctionComponent, useEffect, useState } from "react"; import { CommonPropertyValues, getCommonPropsFromWikidata, -} from "../../utils/wikidata"; -import { OverflowContainer } from "../../lists"; +} from "@slub/edb-ui-utils"; +import { OverflowContainer } from "@slub/edb-basic-components"; interface OwnProps { thingIRI?: string; } -type Props = OwnProps; +export type WikidataAllPropTableProps = OwnProps; -const WikidataAllPropTable: FunctionComponent = ({ thingIRI }) => { +export const WikidataAllPropTable: FunctionComponent< + WikidataAllPropTableProps +> = ({ thingIRI }) => { const [allProps, setAllProps] = useState({}); useEffect(() => { if (!thingIRI) return; @@ -87,5 +89,3 @@ const WikidataAllPropTable: FunctionComponent = ({ thingIRI }) => { ); }; - -export default WikidataAllPropTable; diff --git a/packages/advanced-components/src/wikidata/index.ts b/packages/advanced-components/src/wikidata/index.ts new file mode 100644 index 00000000..3947237d --- /dev/null +++ b/packages/advanced-components/src/wikidata/index.ts @@ -0,0 +1 @@ +export * from "./WikidataAllPropTable"; diff --git a/packages/advanced-components/tsconfig.json b/packages/advanced-components/tsconfig.json new file mode 100644 index 00000000..9db70c96 --- /dev/null +++ b/packages/advanced-components/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "@slub/edb-tsconfig/react-library.json", + "include": ["src"], + "exclude": ["dist", "build", "node_modules"], + "compilerOptions": { + "strict": false, + "resolveJsonModule": true + } +} diff --git a/packages/authorities/package.json b/packages/authorities/package.json new file mode 100644 index 00000000..c1df7923 --- /dev/null +++ b/packages/authorities/package.json @@ -0,0 +1,27 @@ +{ + "name": "@slub/edb-authorities", + "description": "Methods and metadata to search and retrieve data from different authorities", + "version": "0.1.0", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "type": "module", + "license": "MIT", + "scripts": { + "build": "tsup", + "dev": "tsup --watch", + "lint": "eslint \"**/*.ts*\"", + "lint-fix": "eslint --fix \"**/*.ts*\"", + "test": "jest", + "test:watch": "jest --watch --color", + "test:coverage": "jest --coverage" + }, + "devDependencies": { + "@slub/edb-build-helper": "workspace:*" + }, + "dependencies": { + "@slub/edb-core-types": "workspace:*", + "@slub/edb-global-types": "workspace:*", + "lodash-es": "^4.17.21", + "cross-fetch": "^4.0.0" + } +} diff --git a/apps/exhibition-live/components/exhibtion/index.ts b/packages/authorities/src/gnd/index.ts similarity index 100% rename from apps/exhibition-live/components/exhibtion/index.ts rename to packages/authorities/src/gnd/index.ts diff --git a/apps/exhibition-live/components/utils/gnd/prefixes.ts b/packages/authorities/src/gnd/prefixes.ts similarity index 100% rename from apps/exhibition-live/components/utils/gnd/prefixes.ts rename to packages/authorities/src/gnd/prefixes.ts diff --git a/packages/authorities/src/index.ts b/packages/authorities/src/index.ts new file mode 100644 index 00000000..815dfb86 --- /dev/null +++ b/packages/authorities/src/index.ts @@ -0,0 +1,2 @@ +export * from "./lobid"; +export * from "./gnd"; diff --git a/apps/exhibition-live/components/utils/lobid/findEntityWithinLobid.ts b/packages/authorities/src/lobid/findEntityWithinLobid.ts similarity index 64% rename from apps/exhibition-live/components/utils/lobid/findEntityWithinLobid.ts rename to packages/authorities/src/lobid/findEntityWithinLobid.ts index 9016905b..e00d4b60 100644 --- a/apps/exhibition-live/components/utils/lobid/findEntityWithinLobid.ts +++ b/packages/authorities/src/lobid/findEntityWithinLobid.ts @@ -1,5 +1,5 @@ -import { gndBaseIRI } from "../gnd/prefixes"; -import { lobidTypemap } from "../../config"; +import { gndBaseIRI } from "../gnd"; +import fetch from "cross-fetch"; /** * { @@ -18,7 +18,10 @@ import { lobidTypemap } from "../../config"; const lobidSearchURL = "https://lobid.org/gnd/search"; const lobidURL = "https://lobid.org/gnd/"; -const mapTypeName = (typeName: string) => { +const mapTypeName = ( + typeName: string, + lobidTypemap: Record, +) => { const gndType = lobidTypemap[typeName] || typeName; return Array.isArray(gndType) ? gndType : [gndType]; }; @@ -26,10 +29,18 @@ const mapTypeName = (typeName: string) => { const makeTypeFilter = (gndTypes: string[]) => { return gndTypes.map((gndType) => `type:${gndType}`).join(" OR "); }; -const gndIRIToID = (iri: string) => iri.substring(gndBaseIRI.length); +const gndIRIToID = (iri: string) => { + const searchString = "d-nb.info/gnd/"; + const index = iri.indexOf(searchString); + if (index === -1) { + throw new Error(`invalid IRI: ${iri}`); + } + return iri.slice(index + searchString.length); +}; export const findEntityWithinLobid = async ( searchString: string, typeName: string, + lobidTypeMap: Record, limit?: number, format?: string, ) => { @@ -39,7 +50,7 @@ export const findEntityWithinLobid = async ( "?" + new URLSearchParams({ q: searchString, - filter: makeTypeFilter(mapTypeName(typeName)), + filter: makeTypeFilter(mapTypeName(typeName, lobidTypeMap)), size: (limit || 10).toString(), format: format || "json", }).toString(), @@ -51,18 +62,25 @@ export const findEntityWithinLobid = async ( } }; -export const findEntityWithinLobidWithCertainProperty = async ( +export const findEntityWithinLobidWithCertainProperty: ( property: string, searchString: string | undefined, typeName: string, + lobidTypeMap: Record, limit?: number, +) => Promise = async ( + property, + searchString, + typeName, + lobidTypeMap, + limit, ) => { const res = await fetch( lobidSearchURL + "?" + new URLSearchParams({ ...(searchString ? { q: searchString } : {}), - filter: `${makeTypeFilter(mapTypeName(typeName))} AND _exists_:${property}`, + filter: `${makeTypeFilter(mapTypeName(typeName, lobidTypeMap))} AND _exists_:${property}`, size: (limit || 10).toString(), format: "json", }).toString(), @@ -71,7 +89,14 @@ export const findEntityWithinLobidWithCertainProperty = async ( }; export const findEntityWithinLobidByID = async (id: string) => { + console.log("fetching", `${lobidURL}${id}.json`); const res = await fetch(`${lobidURL}${id}.json`); + try { + const result = await res.json(); + return result; + } catch (e) { + throw new Error(`cannot convert response to json: ${e}`); + } return await res.json(); }; diff --git a/packages/authorities/src/lobid/index.ts b/packages/authorities/src/lobid/index.ts new file mode 100644 index 00000000..79e1c36c --- /dev/null +++ b/packages/authorities/src/lobid/index.ts @@ -0,0 +1 @@ +export * from "./findEntityWithinLobid"; diff --git a/packages/authorities/tsconfig.json b/packages/authorities/tsconfig.json new file mode 100644 index 00000000..85d375a5 --- /dev/null +++ b/packages/authorities/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "@slub/edb-tsconfig/base.json", + "include": ["."], + "exclude": ["dist", "build", "node_modules"], + "compilerOptions": { + "lib": ["es2022", "dom"], + "strictNullChecks": false, + "resolveJsonModule": true, + "esModuleInterop": true + } +} + diff --git a/packages/authorities/tsup.config.js b/packages/authorities/tsup.config.js new file mode 100644 index 00000000..85b8dcc3 --- /dev/null +++ b/packages/authorities/tsup.config.js @@ -0,0 +1,5 @@ +import { makeConfigWithExternals } from "@slub/edb-tsup-config/tsup.config.js"; +import pkg from "./package.json"; + +const config = makeConfigWithExternals(pkg); +export default config; diff --git a/packages/basic-components/package.json b/packages/basic-components/package.json new file mode 100644 index 00000000..c10a9ab7 --- /dev/null +++ b/packages/basic-components/package.json @@ -0,0 +1,35 @@ +{ + "name": "@slub/edb-basic-components", + "version": "1.0.0", + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.js", + "require": "./dist/index.cjs", + "default": "./dist/index.js", + "types": "./dist/index.d.ts" + } + }, + "scripts": { + "build": "tsup src/index.tsx --format esm,cjs --dts --external react", + "dev": "tsup src/index.tsx --format esm,cjs --watch --dts --external react", + "lint": "eslint \"**/*.ts*\"", + "lint-fix": "eslint --fix \"**/*.ts*\"" + }, + "dependencies": { + "@slub/edb-state-hooks": "workspace:*", + "@ebay/nice-modal-react": "^1.2", + "next-i18next": "^15.3.0" + }, + "devDependencies": { + "@types/react": "^18.3.3" + }, + "peerDependencies": { + "@mui/material": "^5", + "@mui/icons-material": "^5", + "react": "^18" + } +} diff --git a/apps/exhibition-live/components/form/GenericModal.tsx b/packages/basic-components/src/dialog/GenericModal.tsx similarity index 96% rename from apps/exhibition-live/components/form/GenericModal.tsx rename to packages/basic-components/src/dialog/GenericModal.tsx index dd865af2..45c4c2f6 100644 --- a/apps/exhibition-live/components/form/GenericModal.tsx +++ b/packages/basic-components/src/dialog/GenericModal.tsx @@ -6,7 +6,6 @@ import { DialogActions, DialogContent, DialogContentText, - DialogTitle, IconButton, Toolbar, Typography, @@ -15,12 +14,6 @@ import { Close as CloseIcon } from "@mui/icons-material"; import NiceModal, { useModal } from "@ebay/nice-modal-react"; import { useTranslation } from "next-i18next"; -type GenericModalProps = { - type: string; - id?: string; - extraMessage?: string; -}; - const modalContent = [ { modalType: "moveToTrash", @@ -72,7 +65,13 @@ const modalContent = [ }, ]; -const GenericModal = NiceModal.create( +export type GenericModalProps = { + type: (typeof modalContent)[number]["modalType"]; + id?: string; + extraMessage?: string; +}; + +export const GenericModal = NiceModal.create( ({ type, id, extraMessage }: GenericModalProps) => { const modal = useModal(); const { t } = useTranslation(); @@ -128,5 +127,3 @@ const GenericModal = NiceModal.create( ); }, ); - -export default GenericModal; diff --git a/apps/exhibition-live/components/renderer/MuiEditDialog.tsx b/packages/basic-components/src/dialog/MuiEditDialog.tsx similarity index 98% rename from apps/exhibition-live/components/renderer/MuiEditDialog.tsx rename to packages/basic-components/src/dialog/MuiEditDialog.tsx index 0f458358..463e3d95 100644 --- a/apps/exhibition-live/components/renderer/MuiEditDialog.tsx +++ b/packages/basic-components/src/dialog/MuiEditDialog.tsx @@ -17,7 +17,6 @@ import { Box, Hidden, IconButton, - InputBase, styled, Toolbar, Typography, @@ -47,20 +46,7 @@ const Search = styled("div")(({ theme }) => ({ }, })); -export default function MuiEditDialog({ - children, - open, - title, - onSave, - onCancel, - onClose, - onReload, - onRemove, - onEdit, - editMode, - search, - actions, -}: { +export type MuiEditDialogProps = { onCancel?: () => void; onSave?: () => void; onClose?: () => void; @@ -73,7 +59,21 @@ export default function MuiEditDialog({ search?: React.ReactNode; children?: React.ReactNode; actions?: React.ReactNode; -}) { +}; +export const MuiEditDialog = ({ + children, + open, + title, + onSave, + onCancel, + onClose, + onReload, + onRemove, + onEdit, + editMode, + search, + actions, +}: MuiEditDialogProps) => { const theme = useTheme(); const [forceFullscreen, setForceFullscreen] = useState(false); const fullScreen = useMediaQuery(theme.breakpoints.down("md")); @@ -210,4 +210,4 @@ export default function MuiEditDialog({ ); -} +}; diff --git a/packages/basic-components/src/dialog/index.ts b/packages/basic-components/src/dialog/index.ts new file mode 100644 index 00000000..4062d15b --- /dev/null +++ b/packages/basic-components/src/dialog/index.ts @@ -0,0 +1,2 @@ +export * from "./MuiEditDialog"; +export * from "./GenericModal"; diff --git a/packages/basic-components/src/entity/ClassicEntityCard.stories.tsx b/packages/basic-components/src/entity/ClassicEntityCard.stories.tsx new file mode 100644 index 00000000..f346f696 --- /dev/null +++ b/packages/basic-components/src/entity/ClassicEntityCard.stories.tsx @@ -0,0 +1,29 @@ +import React from "react"; +import { Meta, StoryObj } from "@storybook/react"; +import { ClassicEntityCard, ClassicEntityCardProps } from "./ClassicEntityCard"; + +const meta: Meta = { + title: "components/basic-components/entity/ClassicEntityCard", + component: ClassicEntityCard, +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + args: { + data: { + id: "1", + label: "Sample Label", + title: "Sample Title", + name: "Sample Name", + description: "This is a sample description for the ClassicEntityCard.", + avatar: "https://picsum.photos/300/300", + }, + id: "1", + onBack: () => alert("Back button clicked"), + cardActionChildren: , + detailView:
Detail View Content
, + } as ClassicEntityCardProps, +}; diff --git a/apps/exhibition-live/components/form/lobid/ClassicEntityCard.tsx b/packages/basic-components/src/entity/ClassicEntityCard.tsx similarity index 90% rename from apps/exhibition-live/components/form/lobid/ClassicEntityCard.tsx rename to packages/basic-components/src/entity/ClassicEntityCard.tsx index caaad1a4..5c54d7ab 100644 --- a/apps/exhibition-live/components/form/lobid/ClassicEntityCard.tsx +++ b/packages/basic-components/src/entity/ClassicEntityCard.tsx @@ -29,7 +29,9 @@ type Props = { cardActionChildren?: React.ReactNode; }; -const ClassicEntityCard: FunctionComponent> = ({ +export type ClassicEntityCardProps = Props & Partial; + +export const ClassicEntityCard: FunctionComponent = ({ data, id, onBack, @@ -69,4 +71,3 @@ const ClassicEntityCard: FunctionComponent> = ({
); }; -export default ClassicEntityCard; diff --git a/apps/exhibition-live/components/form/result/ClassicResultPopperItem.tsx b/packages/basic-components/src/entity/ClassicResultPopperItem.tsx similarity index 100% rename from apps/exhibition-live/components/form/result/ClassicResultPopperItem.tsx rename to packages/basic-components/src/entity/ClassicResultPopperItem.tsx diff --git a/packages/basic-components/src/entity/index.ts b/packages/basic-components/src/entity/index.ts new file mode 100644 index 00000000..eae589f5 --- /dev/null +++ b/packages/basic-components/src/entity/index.ts @@ -0,0 +1,2 @@ +export * from "./ClassicEntityCard"; +export * from "./ClassicResultPopperItem"; diff --git a/apps/exhibition-live/components/layout/main-layout/menu/FloatingButton.tsx b/packages/basic-components/src/form/FloatingButton.tsx similarity index 100% rename from apps/exhibition-live/components/layout/main-layout/menu/FloatingButton.tsx rename to packages/basic-components/src/form/FloatingButton.tsx diff --git a/apps/exhibition-live/components/form/wizard/HorizontalNonLinearStepper.tsx b/packages/basic-components/src/form/HorizontalNonLinearStepper.tsx similarity index 95% rename from apps/exhibition-live/components/form/wizard/HorizontalNonLinearStepper.tsx rename to packages/basic-components/src/form/HorizontalNonLinearStepper.tsx index 51153552..0b7f2f62 100644 --- a/apps/exhibition-live/components/form/wizard/HorizontalNonLinearStepper.tsx +++ b/packages/basic-components/src/form/HorizontalNonLinearStepper.tsx @@ -6,17 +6,17 @@ import StepButton from "@mui/material/StepButton"; import Button from "@mui/material/Button"; import Typography from "@mui/material/Typography"; -type Step = { +export type Step = { label: string; content: React.ReactNode; }; -type HorizontalNonLinearStepperProps = { +export type HorizontalNonLinearStepperProps = { steps: Step[]; }; -export default function HorizontalNonLinearStepper({ +export const HorizontalNonLinearStepper = ({ steps, -}: HorizontalNonLinearStepperProps) { +}: HorizontalNonLinearStepperProps) => { const [activeStep, setActiveStep] = React.useState(0); const [completed, setCompleted] = React.useState<{ [k: number]: boolean; @@ -130,4 +130,4 @@ export default function HorizontalNonLinearStepper({ {steps[activeStep]?.content} ); -} +}; diff --git a/packages/basic-components/src/form/Searchbar.tsx b/packages/basic-components/src/form/Searchbar.tsx new file mode 100644 index 00000000..173f58a0 --- /dev/null +++ b/packages/basic-components/src/form/Searchbar.tsx @@ -0,0 +1,38 @@ +import { Box, Toolbar } from "@mui/material"; +import React from "react"; +import MuiDrawer from "@mui/material/Drawer"; +import type { SearchbarWithFloatingButtonProps } from "./SearchbarWithFloatingButton"; + +export type SearchbarProps = { + drawerWidth: number; + open: boolean; +} & SearchbarWithFloatingButtonProps; + +export const Searchbar = ({ open, drawerWidth, children }: SearchbarProps) => { + try { + return ( + + + + {children} + + + ); + } catch (e) { + console.error(e); + return null; + } +}; diff --git a/packages/basic-components/src/form/SearchbarWithFloatingButton.tsx b/packages/basic-components/src/form/SearchbarWithFloatingButton.tsx new file mode 100644 index 00000000..b2a67008 --- /dev/null +++ b/packages/basic-components/src/form/SearchbarWithFloatingButton.tsx @@ -0,0 +1,34 @@ +import { useRightDrawerState } from "@slub/edb-state-hooks"; +import React, { useCallback } from "react"; +import { FloatingButton } from "./FloatingButton"; +import { Searchbar } from "./Searchbar"; + +export type SearchbarWithFloatingButtonProps = { + children?: React.ReactNode; +}; + +export const SearchbarWithFloatingButton = ({ + children, +}: SearchbarWithFloatingButtonProps) => { + const { + open: rightDrawerOpened, + setOpen: setRightDrawerOpened, + width: rightDrawerWidth, + setWidth: setRightDrawerWidth, + } = useRightDrawerState(); + const toggleRightDrawer = useCallback(() => { + setRightDrawerOpened((prev: boolean) => !prev); + }, [setRightDrawerOpened]); + return ( + <> + + + {rightDrawerOpened && children ? children : null} + + + ); +}; diff --git a/packages/basic-components/src/form/index.ts b/packages/basic-components/src/form/index.ts new file mode 100644 index 00000000..1d886c31 --- /dev/null +++ b/packages/basic-components/src/form/index.ts @@ -0,0 +1,4 @@ +export * from "./FloatingButton"; +export * from "./Searchbar"; +export * from "./SearchbarWithFloatingButton"; +export * from "./HorizontalNonLinearStepper"; diff --git a/packages/basic-components/src/index.tsx b/packages/basic-components/src/index.tsx new file mode 100644 index 00000000..097057d0 --- /dev/null +++ b/packages/basic-components/src/index.tsx @@ -0,0 +1,6 @@ +export * from "./list"; +export * from "./entity"; +export * from "./overflow"; +export * from "./utils"; +export * from "./dialog"; +export * from "./form"; diff --git a/packages/basic-components/src/list/ClassicResultListItem.stories.tsx b/packages/basic-components/src/list/ClassicResultListItem.stories.tsx new file mode 100644 index 00000000..2b874e31 --- /dev/null +++ b/packages/basic-components/src/list/ClassicResultListItem.stories.tsx @@ -0,0 +1,25 @@ +import React from "react"; +import { Meta, StoryObj } from "@storybook/react"; +import { ClassicResultListItem } from "./ClassicResultListItem"; + +export default { + title: "components/basic-components/list/ClassicResultListItem", + component: ClassicResultListItem, +} as Meta; + +type Story = StoryObj; + +export const Primary: Story = { + args: { + id: "list-item-1", + index: 0, + onSelected: (id: string, index: number) => + console.log(`Selected: ${id} at index ${index}`), + avatar: "http://example.com/avatar.png", + label: "Primary Example", + secondary: "This is a secondary text example", + category: "Category Example", + altAvatar: "A", + selected: false, + }, +}; diff --git a/apps/exhibition-live/components/form/result/ClassicResultListItem.tsx b/packages/basic-components/src/list/ClassicResultListItem.tsx similarity index 88% rename from apps/exhibition-live/components/form/result/ClassicResultListItem.tsx rename to packages/basic-components/src/list/ClassicResultListItem.tsx index 19f95423..b934855a 100644 --- a/apps/exhibition-live/components/form/result/ClassicResultListItem.tsx +++ b/packages/basic-components/src/list/ClassicResultListItem.tsx @@ -1,28 +1,21 @@ -// @flow import { Avatar, - Divider, - IconButton, ListItem, ListItemAvatar, ListItemButton, ListItemButtonProps, ListItemProps, ListItemText, - Stack, - Typography, } from "@mui/material"; import { useTheme } from "@mui/material/styles"; import * as React from "react"; import { FunctionComponent, useCallback, useEffect, useState } from "react"; -import { ClassicResultPopperItem } from "./ClassicResultPopperItem"; import { useKeyEventForSimilarityFinder, useSimilarityFinderState, -} from "../../state"; -import { Check } from "@mui/icons-material"; -import { OverflowContainer } from "../../lists"; -import { OverflowChip } from "../../lists/OverflowChip"; +} from "@slub/edb-state-hooks"; +import { OverflowChip, OverflowContainer } from "../overflow"; +import { ClassicResultPopperItem } from "../entity"; type OwnProps = { id: string; @@ -40,9 +33,11 @@ type OwnProps = { popperClosed?: boolean; }; -type Props = OwnProps & ListItemButtonProps; +export type ClassicResultListItemProps = OwnProps & ListItemButtonProps; -const ClassicResultListItem: FunctionComponent = ({ +export const ClassicResultListItem: FunctionComponent< + ClassicResultListItemProps +> = ({ id, index, onSelected, @@ -117,6 +112,7 @@ const ClassicResultListItem: FunctionComponent = ({ {label} @@ -146,5 +142,3 @@ const ClassicResultListItem: FunctionComponent = ({ ); }; - -export default ClassicResultListItem; diff --git a/apps/exhibition-live/components/form/result/ClassicResultListWrapper.tsx b/packages/basic-components/src/list/ClassicResultListWrapper.tsx similarity index 58% rename from apps/exhibition-live/components/form/result/ClassicResultListWrapper.tsx rename to packages/basic-components/src/list/ClassicResultListWrapper.tsx index 2e5507a0..f00c3750 100644 --- a/apps/exhibition-live/components/form/result/ClassicResultListWrapper.tsx +++ b/packages/basic-components/src/list/ClassicResultListWrapper.tsx @@ -5,24 +5,19 @@ import { Paper, Grid, } from "@mui/material"; -import { FunctionComponent, useCallback, useState } from "react"; +import { FunctionComponent } from "react"; import { useTranslation } from "next-i18next"; -type Props = { +export type ClassicResultListWrapperProps = { label?: string; - selected?: boolean; children?: React.ReactNode; handleClick?: (id: undefined) => void; hitCount?: number; }; -const ClassicResultListWrapper: FunctionComponent = ({ - label, - selected, - children, - handleClick, - hitCount, -}) => { +export const ClassicResultListWrapper: FunctionComponent< + ClassicResultListWrapperProps +> = ({ label, children, handleClick, hitCount }) => { const { t } = useTranslation(); return ( @@ -34,7 +29,6 @@ const ClassicResultListWrapper: FunctionComponent = ({ onClick={handleClick} > = ({ mb: "2px", }} secondary={ - selected - ? hitCount > 0 - ? t("found hits", { count: hitCount }) - : t("no hits") - : t("datasource disabled") + hitCount > 0 + ? t("found hits", { count: hitCount }) + : t("no hits") } secondaryTypographyProps={{ noWrap: true, @@ -60,25 +52,21 @@ const ClassicResultListWrapper: FunctionComponent = ({ - {selected && ( - <> - - {children} - - - - )} + <> + + {children} + + + ); }; - -export default ClassicResultListWrapper; diff --git a/packages/basic-components/src/list/index.ts b/packages/basic-components/src/list/index.ts new file mode 100644 index 00000000..6c752b00 --- /dev/null +++ b/packages/basic-components/src/list/index.ts @@ -0,0 +1,2 @@ +export * from "./ClassicResultListItem"; +export * from "./ClassicResultListWrapper"; diff --git a/packages/basic-components/src/overflow/OverflowChip.stories.tsx b/packages/basic-components/src/overflow/OverflowChip.stories.tsx new file mode 100644 index 00000000..2540218e --- /dev/null +++ b/packages/basic-components/src/overflow/OverflowChip.stories.tsx @@ -0,0 +1,18 @@ +import React from "react"; +import { Meta, StoryObj } from "@storybook/react"; +import { OverflowChip } from "./OverflowChip"; + +export default { + title: "components/basic-components/overflow/OverflowChip", + component: OverflowChip, +} as Meta; + +type Story = StoryObj; + +export const Primary: Story = { + args: { + label: "Example Chip", + secondary: "Detailed description here", + entityIRI: "http://example.com/entity", + }, +}; diff --git a/apps/exhibition-live/components/lists/OverflowChip.tsx b/packages/basic-components/src/overflow/OverflowChip.tsx similarity index 70% rename from apps/exhibition-live/components/lists/OverflowChip.tsx rename to packages/basic-components/src/overflow/OverflowChip.tsx index 27191765..ff4f1f98 100644 --- a/apps/exhibition-live/components/lists/OverflowChip.tsx +++ b/packages/basic-components/src/overflow/OverflowChip.tsx @@ -1,23 +1,23 @@ -import { useState, MouseEvent, useMemo, useCallback } from "react"; -import { Chip, Tooltip, Typography } from "@mui/material"; +import { useState, MouseEvent, useCallback } from "react"; +import { Chip, Tooltip } from "@mui/material"; import NiceModal from "@ebay/nice-modal-react"; -import { EntityDetailModal } from "../form/show/EntityDetailModal"; +import { useAdbContext } from "@slub/edb-state-hooks"; -type OverflowContainerProps = { +export type OverflowChipProps = { label: React.ReactNode; secondary?: React.ReactNode; entityIRI?: string; }; -const OverflowText = ({ children }: { children: string }) => { - return {children}; -}; export const OverflowChip = ({ label, entityIRI, secondary, -}: OverflowContainerProps) => { +}: OverflowChipProps) => { const [tooltipEnabled, setTooltipEnabled] = useState(false); + const { + components: { EntityDetailModal }, + } = useAdbContext(); const showDetailModal = useCallback( (e: MouseEvent) => { @@ -25,7 +25,7 @@ export const OverflowChip = ({ e.preventDefault(); NiceModal.show(EntityDetailModal, { entityIRI, data: {} }); }, - [entityIRI], + [entityIRI, EntityDetailModal], ); const handleShouldShow = useCallback( diff --git a/apps/exhibition-live/components/lists/OverflowContainer.tsx b/packages/basic-components/src/overflow/OverflowContainer.tsx similarity index 80% rename from apps/exhibition-live/components/lists/OverflowContainer.tsx rename to packages/basic-components/src/overflow/OverflowContainer.tsx index c67735fc..10be599a 100644 --- a/apps/exhibition-live/components/lists/OverflowContainer.tsx +++ b/packages/basic-components/src/overflow/OverflowContainer.tsx @@ -1,19 +1,21 @@ import React, { useState, MouseEvent, useCallback } from "react"; -import { Tooltip, Typography, TypographyOwnProps } from "@mui/material"; +import { Box, Tooltip, TypographyOwnProps } from "@mui/material"; -type OverflowContainerProps = { +type Props = { children: React.ReactNode; tooltip?: React.ReactNode; density?: "comfortable" | "compact" | "spacious"; useParentTarget?: boolean; }; + +export type OverflowContainerProps = Props & Partial; export const OverflowContainer = ({ children, tooltip, useParentTarget, density, ...props -}: OverflowContainerProps & Partial) => { +}: OverflowContainerProps) => { const [tooltipEnabled, setTooltipEnabled] = useState(false); const handleShouldShow = useCallback( @@ -39,17 +41,17 @@ export const OverflowContainer = ({ open={tooltipEnabled} onClose={() => setTooltipEnabled(false)} > - {children} - + ); }; diff --git a/packages/basic-components/src/overflow/OverflowText.stories.tsx b/packages/basic-components/src/overflow/OverflowText.stories.tsx new file mode 100644 index 00000000..29ce9ae0 --- /dev/null +++ b/packages/basic-components/src/overflow/OverflowText.stories.tsx @@ -0,0 +1,16 @@ +import React from "react"; +import { Meta, StoryObj } from "@storybook/react"; +import { OverflowText } from "./OverflowText"; + +export default { + title: "components/basic-components/overflow/OverflowText", + component: OverflowText, +} as Meta; + +type Story = StoryObj; + +export const Primary: Story = { + args: { + children: "A long text that needs to be stripped", + }, +}; diff --git a/packages/basic-components/src/overflow/OverflowText.tsx b/packages/basic-components/src/overflow/OverflowText.tsx new file mode 100644 index 00000000..7aad1b59 --- /dev/null +++ b/packages/basic-components/src/overflow/OverflowText.tsx @@ -0,0 +1,5 @@ +import { Typography } from "@mui/material"; + +export const OverflowText = ({ children }: { children: string }) => { + return {children}; +}; diff --git a/packages/basic-components/src/overflow/index.ts b/packages/basic-components/src/overflow/index.ts new file mode 100644 index 00000000..4686b2d1 --- /dev/null +++ b/packages/basic-components/src/overflow/index.ts @@ -0,0 +1,3 @@ +export * from "./OverflowContainer"; +export * from "./OverflowText"; +export * from "./OverflowChip"; diff --git a/apps/exhibition-live/components/form/utils/Pulse.tsx b/packages/basic-components/src/utils/Pulse.tsx similarity index 90% rename from apps/exhibition-live/components/form/utils/Pulse.tsx rename to packages/basic-components/src/utils/Pulse.tsx index 7307a095..542b23bb 100644 --- a/apps/exhibition-live/components/form/utils/Pulse.tsx +++ b/packages/basic-components/src/utils/Pulse.tsx @@ -39,7 +39,7 @@ const PulsatingDot = styled.div` &:before { animation: pulseRing 1.25s cubic-bezier(0.215, 0.61, 0.355, 1) infinite; background-color: ${({ dotColor, theme }) => - dotColor || (theme as Theme).palette.primary.main}; + dotColor || (theme as Theme).palette?.primary?.main}; border-radius: ${({ borderRadius }) => borderRadius || "50%"}; content: ""; display: block; @@ -55,13 +55,15 @@ const PulsatingDot = styled.div` } `; +export type PulseProps = PulsatingDotProps & { children: React.ReactNode }; + export const Pulse = ({ dotColor, borderRadius, boxHeight, pulse, children, -}: PulsatingDotProps & { children: React.ReactNode }) => +}: PulseProps) => pulse ? ( -r [options] + ``` + + **Required Options:** + +- `-s, --start `: The commit SHA where you want to start the testing. +- `-r, --remote `: The path to your local Git repository or a remote Git URL. + + **Optional Options:** + +- `-e, --end `: The commit SHA where you want to end the testing (defaults to `HEAD`). +- `-c, --clone-each`: Clone the repository for each commit being tested (useful if your tests modify the repository state). +- `-h, --help`: Display the help message. + +### How it Works + +The script iterates through the specified commit range and performs the following steps for each commit: + +1. **Checkout:** It checks out the commit within the cloned repository. +2. **Install Dependencies (if needed):** Runs `bun install` if the `-c` (clone each time) option is used. +3. **Run Cypress Tests:** It executes the configured Cypress test suite. +4. **Collect Results:** The output of the Cypress test run, along with any relevant logs, is saved to a file named with the commit SHA. + +### Example + +```bash +./bug-hunter.sh -s abc123def456 -r ~/my-project -e fgh789ijk012 -c +``` + +This command will run the Cypress tests for each commit from `abc123def456` to `fgh789ijk012` in the repository located at `~/my-project`. The `-c` flag ensures a clean checkout for every commit. + +#### Output + +The script creates log files (named using the commit SHA) containing the output of each Cypress test run. You can analyze these log files to identify at which point the bug was introduced or fixed. + +### Notes + +- copy this script to an empty directory not under version control. +- Adjust the script's configuration (e.g., the path to your Cypress test file) to match your project setup. + - needs to be done directly in the script +- Consider using a more sophisticated log analysis tool or integrating with a CI/CD pipeline for easier result interpretation in larger projects or for automated bug hunting workflows. diff --git a/packages/build-helper/bug-hunter.sh b/packages/build-helper/bug-hunter.sh new file mode 100755 index 00000000..0db7759e --- /dev/null +++ b/packages/build-helper/bug-hunter.sh @@ -0,0 +1,153 @@ +#!/usr/bin/env bash + +set -e # Exit immediately on error + +# Check for required arguments +if [ -z "$1" ] || [ -z "$2" ]; then + echo "Usage: $0 " + exit 1 +fi + +# Set defaults +STARTING_COMMIT_SHA="" +END_COMMIT_SHA="" +FOLDER_OR_GIT_REMOTE="" +CLONE_EACH_TIME=false # Default to not cloning each time +ORIGINAL_FOLDER=$PWD +MAIN_APP="apps/exhibition-live" +PROJECT_DIR="project-checkout" + +# Function to display help message +show_help() { + echo "Usage: $0 -s -e -r [options]" + echo "Options:" + echo " -s, --start Starting commit SHA (required)" + echo " -e, --end Ending commit SHA (defaults to HEAD)" + echo " -r, --remote Folder or Git remote URL (required)" + echo " -c, --clone-each Clone repository for each commit (optional)" + echo " -h, --help Display this help message" +} + +# Process command-line arguments using getopts +while getopts ":s:e:r:ch" opt; do + case $opt in + s) STARTING_COMMIT_SHA="$OPTARG" ;; + e) END_COMMIT_SHA="$OPTARG" ;; + r) FOLDER_OR_GIT_REMOTE="$OPTARG" ;; + c) CLONE_EACH_TIME=true ;; + h) show_help && exit 0 ;; + \?) echo "Invalid option: -$OPTARG" >&2; show_help && exit 1 ;; + :) echo "Option -$OPTARG requires an argument." >&2; show_help && exit 1 ;; + esac +done + +# Check for required arguments +if [ -z "$STARTING_COMMIT_SHA" ] || [ -z "$FOLDER_OR_GIT_REMOTE" ]; then + echo "Error: -s and -r options are required." >&2 + show_help && exit 1 +fi + +# If END_COMMIT_SHA is not provided, default to HEAD +if [ -z "$END_COMMIT_SHA" ]; then + END_COMMIT_SHA="HEAD" +fi + +# ... (Rest of your script) + +echo "STARTING_COMMIT =$STARTING_COMMIT_SHA" +echo "FOLDER_OR_GIT_REMOTE =$FOLDER_OR_GIT_REMOTE" + +# Function to run tests for a specific commit +run_tests_for_commit() { + local commit_sha=$1 + + echo "Testing commit: $commit_sha" + + + # nonzero and not false + if [ -n CLONE_EACH_TIME -a "$CLONE_EACH_TIME" != "false" ]; then + cd "$ORIGINAL_FOLDER" + rm -rf "$PROJECT_DIR" + git clone -q "$FOLDER_OR_GIT_REMOTE" "$PROJECT_DIR" + cd "$PROJECT_DIR" + fi + + git stash + git checkout -q "$commit_sha" + + bun i + bun build:packages || true + + cp ../personList.cy.js "$MAIN_APP/cypress/e2e/" + cp ../cypress.config.ts "$MAIN_APP/" + cp ../.env.local "$MAIN_APP/" + + + cd "$MAIN_APP" + # Run development server in the background + bun run dev:vite & + vite_pid=$! + + # Give the server time to start + sleep 2 + + bun add @testing-library/cypress --dev + echo "import '@testing-library/cypress/add-commands'" >> cypress/support/commands.ts + + # Run Cypress tests, redirecting output to a log file + COMMIT_SHA=${commit_sha} bunx cypress run --headed --spec ./cypress/e2e/personList.cy.js 2>&1 | tee "$ORIGINAL_FOLDER/${commit_sha}.cypress.log" || true + + echo "Test run ready" + + # Kill the development server + kill "$vite_pid" || true + killall node || true + + + local SCREENSHOT_FOLDER="./cypress/screenshots/personList.cy.js" + + if [ -d "${SCREENSHOT_FOLDER}" ]; then + echo "Will copy screenshots" + mv "${SCREENSHOT_FOLDER}" "${ORIGINAL_FOLDER}/${commit_sha}" + else + echo "no screenshots to copy" + fi + + cd "$ORIGINAL_FOLDER/$PROJECT_DIR" + + echo "Finished testing commit: $commit_sha" + + sleep 2 +} + +# --- Main Script --- + +#check if folder exists + +if [ -d "$PROJECT_DIR" ]; then + echo "Folder exists" + cd "$PROJECT_DIR" + git stash + git checkout -q $END_COMMIT_SHA + #git pull +else + echo "Folder does not exist" + # Clone only once at the beginning + git clone -q "$FOLDER_OR_GIT_REMOTE" "$PROJECT_DIR" + cd "$PROJECT_DIR" + git checkout -q $END_COMMIT_SHA +fi + +# Get the list of commits +commit_list=$(git rev-list "$STARTING_COMMIT_SHA"..HEAD | tac) + +echo "Commits to test: $commit_list" + +# Iterate over the commit list and run tests +for commit_sha in $commit_list; do + run_tests_for_commit "$commit_sha" +done + +cd "$ORIGINAL_FOLDER" + +echo "All commits tested." diff --git a/packages/build-helper/get-dependencies.js b/packages/build-helper/get-dependencies.js new file mode 100755 index 00000000..cf2ca5cd --- /dev/null +++ b/packages/build-helper/get-dependencies.js @@ -0,0 +1,151 @@ +#!/usr/bin/env node +const ts = require("typescript"); +const glob = require("glob"); +const path = require("path"); +const fs = require("fs"); +const fetch = require("npm-registry-fetch"); + +function checkTypes(packageName) { + // Fetching package metadata from the npm registry + return fetch(`https://registry.npmjs.org/${packageName}`) + .then((response) => response.json()) + .then((data) => { + // Look for the latest version key + const latestVersion = data["dist-tags"].latest; + const latestData = data.versions[latestVersion]; + + // Check if 'types' or 'typings' field exists + if (latestData.types || latestData.typings) { + return true; + } else { + return false; + } + }) + .catch((error) => { + console.error("Error fetching package data:", error); + }); +} + +function extractPackageName(importString) { + // Regular expression to match both scoped and non-scoped package names + const packageNameRegex = /^(@[^\/]+\/[^\/]+|[^\/]+)/; + + // Apply the regex to extract the package name + const match = importString.match(packageNameRegex); + if (match) { + return match[0]; + } else { + return null; // or throw an error depending on how you want to handle no matches + } +} +function getLatestVersion(packageName) { + // Fetching package metadata from the npm registry + return fetch(`https://registry.npmjs.org/${packageName}/latest`) + .then((response) => response.json()) + .then((data) => { + //console.log(`Latest version of ${packageName} is: ${data.version}`); + return data.version; + }); +} + +if (!process.argv[2]) { + console.error( + "Please provide a path to the directory containing TypeScript files", + ); + process.exit(1); +} +// Path to the directory containing TypeScript files +const DIRECTORY_PATH = `${process.argv[2]}/**/*.ts*`; + +// Helper function to parse TypeScript file and extract external module names +function extractImports(filePath) { + const fileContents = fs.readFileSync(filePath, "utf8"); + const sourceFile = ts.createSourceFile( + filePath, + fileContents, + ts.ScriptTarget.ES2015, + true, + ); + + const imports = []; + ts.forEachChild(sourceFile, (node) => { + if (ts.isImportDeclaration(node) && node.moduleSpecifier) { + const specifier = node.moduleSpecifier.text; + if (specifier.startsWith(".") === false) { + // Filter out relative imports + imports.push(specifier); + } + } + }); + return imports; +} + +// Read all TypeScript files and extract imports +glob(DIRECTORY_PATH, async (err, files) => { + if (err) { + console.error("Error finding files", err); + return; + } + + const allImports = new Set(); + files.forEach((file) => { + const imports = extractImports(file); + imports.forEach((imp) => { + const packageName = extractPackageName(imp); + allImports.add(packageName); + }); + }); + const convertToTypesPackageName = (name) => + `@types/${name.replace(/^@([^\/]+)\/(.+)$/, "$1__$2").replace(/\/$/, "")}`; + + const filteredImports = Array.from(allImports).filter( + (imp) => !imp.startsWith("@slub"), + ); + const workspaceImports = Array.from(allImports).filter((imp) => + imp.startsWith("@slub"), + ); + + const dependenciesWithInfo = await Promise.all( + filteredImports.map(async (dep) => { + const version = await getLatestVersion(dep); + const hasTypes = await checkTypes(dep); + let devDependency = null; + if (!hasTypes) { + const typesPackage = convertToTypesPackageName(dep); + try { + const typesVersion = await getLatestVersion(typesPackage); + devDependency = { dep: typesPackage, version: typesVersion }; + } catch (e) {} + } + return { dep, version, hasTypes, devDependency }; + }), + ); + + const dependencies = Object.fromEntries([ + ...workspaceImports.map((dep) => { + return [dep, "workspace:*"]; + }), + ...dependenciesWithInfo.map((dep) => { + return [dep.dep, `^${dep.version}`]; + }), + ]); + + const devDependencies = Object.fromEntries( + dependenciesWithInfo + .filter((dep) => dep.devDependency) + .map((dep) => { + return [dep.devDependency.dep, `^${dep.devDependency.version}`]; + }), + ); + + console.log( + JSON.stringify( + { + dependencies, + devDependencies, + }, + null, + 2, + ), + ); +}); diff --git a/packages/build-helper/make-package-json.js b/packages/build-helper/make-package-json.js index f21f5057..12bcd643 100755 --- a/packages/build-helper/make-package-json.js +++ b/packages/build-helper/make-package-json.js @@ -1,3 +1,4 @@ +#!/usr/bin/env node const fs = require("fs"); const path = require("path"); diff --git a/packages/build-helper/package.json b/packages/build-helper/package.json index 315a48d7..18dfce53 100644 --- a/packages/build-helper/package.json +++ b/packages/build-helper/package.json @@ -7,6 +7,11 @@ "access": "public" }, "bin": { - "make-package-json": "./make-package-json.js" + "make-package-json": "./make-package-json.js", + "get-dependecies": "./get-dependencies.js" + }, + "devDependencies": { + "npm-registry-fetch": "^17.0.1", + "typescript": "^5.4.5" } } diff --git a/packages/build-helper/templates/react-lib-package.json b/packages/build-helper/templates/react-lib-package.json new file mode 100644 index 00000000..f4a2c0a1 --- /dev/null +++ b/packages/build-helper/templates/react-lib-package.json @@ -0,0 +1,34 @@ +{ + "version": "1.0.0", + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.js", + "require": "./dist/index.cjs", + "default": "./dist/index.js", + "types": "./dist/index.d.ts" + } + }, + "scripts": { + "build": "tsup src/index.tsx --format esm,cjs --dts --external react", + "dev": "tsup src/index.tsx --format esm,cjs --watch --dts --external react", + "lint": "eslint \"**/*.ts*\"", + "lint-fix": "eslint --fix \"**/*.ts*\"", + "test": "jest", + "test:watch": "jest --watch --color", + "test:coverage": "jest --coverage", + "doc": "typedoc" + }, + "devDependencies": { + "@slub/edb-tsconfig": "workspace:*", + "@slub/edb-tsup-config": "workspace:*", + "@types/jest": "^29.5.12" + }, + "peerDependencies": { + "next": ">14", + "react": "^16.9.0 || ^17.0.0 || ^18" + } +} diff --git a/packages/config-helper/jest.config.js b/packages/config-helper/jest.config.js new file mode 100644 index 00000000..84ac7dc2 --- /dev/null +++ b/packages/config-helper/jest.config.js @@ -0,0 +1,10 @@ +export default { + transform: { + "^.+\\.(ts|tsx)$": [ + "ts-jest", + { + useESM: true, + }, + ], + }, +}; diff --git a/packages/config-helper/package.json b/packages/config-helper/package.json new file mode 100644 index 00000000..ff3cc0f6 --- /dev/null +++ b/packages/config-helper/package.json @@ -0,0 +1,37 @@ +{ + "name": "@slub/edb-config-helper", + "version": "1.0.0", + "description": "helper functions to facilitate configuration of the EDB specific instances", + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.js", + "require": "./dist/index.cjs", + "default": "./dist/index.js", + "types": "./dist/index.d.ts" + } + }, + "scripts": { + "build": "tsup", + "dev": "tsup --watch", + "lint": "eslint \"**/*.ts*\"", + "lint-fix": "eslint --fix \"**/*.ts*\"", + "test": "jest", + "test:watch": "jest --watch --color", + "test:coverage": "jest --coverage", + "doc": "typedoc" + }, + "devDependencies": { + "@slub/edb-build-helper": "workspace:*", + "@slub/edb-tsconfig": "workspace:*", + "@slub/edb-tsup-config": "workspace:*", + "@slub/edb-global-types": "workspace:*", + "eslint-config-edb": "workspace:*", + "@types/jest": "^29", + "typescript": "^5" + } +} + diff --git a/packages/config-helper/src/fromSimplifiedConfig.ts b/packages/config-helper/src/fromSimplifiedConfig.ts new file mode 100644 index 00000000..d654e5df --- /dev/null +++ b/packages/config-helper/src/fromSimplifiedConfig.ts @@ -0,0 +1,28 @@ +import { EdbConfRaw, SimplifiedEndpointConfig } from "@slub/edb-global-types"; + +export const fromSimplifiedEndpointConfig = ({ + baseIRI, + entityBaseIRI, + endpoint, + jsonldContext, +}: SimplifiedEndpointConfig): EdbConfRaw => + ({ + BASE_IRI: baseIRI, + namespaceBase: baseIRI, + defaultPrefix: baseIRI, + walkerOptions: { + maxRecursion: 6, + maxRecursionEachRef: 6, + skipAtLevel: 10, + omitEmptyArrays: true, + omitEmptyObjects: true, + }, + defaultJsonldContext: { + "@vocab": baseIRI, + ...(jsonldContext || {}), + }, + defaultQueryBuilderOptions: { + prefixes: { [""]: baseIRI, entity: entityBaseIRI }, + }, + sparqlEndpoint: endpoint, + }) as EdbConfRaw; diff --git a/packages/config-helper/src/index.ts b/packages/config-helper/src/index.ts new file mode 100644 index 00000000..03470508 --- /dev/null +++ b/packages/config-helper/src/index.ts @@ -0,0 +1 @@ +export * from "./fromSimplifiedConfig"; diff --git a/packages/config-helper/tsconfig.json b/packages/config-helper/tsconfig.json new file mode 100644 index 00000000..44fc2094 --- /dev/null +++ b/packages/config-helper/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "@slub/edb-tsconfig/base.json", + "include": ["."], + "exclude": ["dist", "build", "node_modules"], + "compilerOptions": { + "resolveJsonModule": true + } +} diff --git a/packages/config-helper/tsup.config.js b/packages/config-helper/tsup.config.js new file mode 100644 index 00000000..85b8dcc3 --- /dev/null +++ b/packages/config-helper/tsup.config.js @@ -0,0 +1,5 @@ +import { makeConfigWithExternals } from "@slub/edb-tsup-config/tsup.config.js"; +import pkg from "./package.json"; + +const config = makeConfigWithExternals(pkg); +export default config; diff --git a/packages/config-helper/typedoc.js b/packages/config-helper/typedoc.js new file mode 100644 index 00000000..6edd6a70 --- /dev/null +++ b/packages/config-helper/typedoc.js @@ -0,0 +1,4 @@ +export default { + extends: ["@slub/edb-tsconfig/typedoc.base.json"], + entryPoints: ["src/index.ts"], +}; diff --git a/packages/core-types/index.d.ts b/packages/core-types/index.d.ts index a690d11d..0f9975e2 100644 --- a/packages/core-types/index.d.ts +++ b/packages/core-types/index.d.ts @@ -1,5 +1,7 @@ import { Bindings, DatasetCore, Quad, ResultStream } from "@rdfjs/types"; import { NamespaceBuilder } from "@rdfjs/namespace"; +import { DeclarativeMapping } from "@slub/edb-ui-utils"; +export type * from "./settings"; export type Prefixes = { [k: string]: string; @@ -24,12 +26,15 @@ export type PrimaryFieldExtract = Partial<{ description: FieldExtractDeclaration; image: FieldExtractDeclaration; }>; -export type PrimaryFieldDeclaration = { - [typeName: string]: PrimaryField; +export type PrimaryFieldDeclaration = { + [typeName: Key]: PrimaryField; }; -export type PrimaryFieldExtractDeclaration = { - [typeName: string]: PrimaryFieldExtract; +export type PrimaryFieldExtractDeclaration< + T = any, + Key extends string = string, +> = { + [typeName: Key]: PrimaryFieldExtract; }; export type PrimaryFieldResults = { @@ -45,37 +50,44 @@ export type NamedEntityData = { export type NamedAndTypedEntity = NamedEntityData & { "@type": string; }; + +export type StringToIRIFn = (property: string) => string; +export type IRIToStringFn = (iri: string) => string; export interface SparqlBuildOptions { base?: string; - prefixes?: Record; + prefixes?: Record; + propertyToIRI: StringToIRIFn; + typeIRItoTypeName: IRIToStringFn; + primaryFields: PrimaryFieldDeclaration; + primaryFieldExtracts: PrimaryFieldExtractDeclaration; + sparqlFlavour?: SPARQLFlavour; } - export interface SelectFetchOptions { withHeaders?: boolean; } -export type CRUDFunctions = { - updateFetch: ( - query: string, - ) => Promise< - | ResultStream - | boolean - | void - | ResultStream - | ResultStream - | Response - >; - constructFetch: (query: string) => Promise; - selectFetch: (query: string, options?: SelectFetchOptions) => Promise; - askFetch: (query: string) => Promise; -}; - export type SPARQLCRUDOptions = { queryBuildOptions?: SparqlBuildOptions; defaultPrefix: string; maxRecursion?: number; }; +export type ResultBindings = any[]; + +export type RDFSelectResult = { + head: { + vars: string[]; + }; + results: { + bindings: ResultBindings; + }; +}; + +export type SelectFetchOverload = { + (query: string, options: { withHeaders: true }): Promise; + (query: string, options?: { withHeaders?: false }): Promise; +}; + export type CRUDFunctions = { updateFetch: ( query: string, @@ -88,7 +100,7 @@ export type CRUDFunctions = { | Response >; constructFetch: (query: string) => Promise; - selectFetch: (query: string, options?: SelectFetchOptions) => Promise; + selectFetch: SelectFetchOverload; askFetch: (query: string) => Promise; }; @@ -107,11 +119,21 @@ export type SparqlEndpoint = { | "worker" | "blazegraph" | "virtuoso" - | "qlever"; + | "qlever" + | "rest"; }; export type SPARQLFlavour = "default" | "oxigraph" | "blazegraph" | "allegro"; +export type WorkerProvider = Record< + NonNullable, + | (>( + endpointConfig: SparqlEndpoint, + options?: T, + ) => CRUDFunctions) + | null +>; + export type QueryOptions = { defaultPrefix: string; queryBuildOptions: SparqlBuildOptions; @@ -125,3 +147,38 @@ export type BasicThingInformation = { category?: string; allProps?: Record; }; + +export type QueryBuilderOptions = { + prefixes: Prefixes; + defaultPrefix: string; +}; + +export type Permission = { + view: boolean; + edit: boolean; +}; + +export type PermissionDeclaration = { + [typeName in T]: Permission; +}; + +export type SameAsTypeMap = Record; + +export type NormDataMapping = { + label: string; + mapping: DeclarativeMapping; + sameAsTypeMap: SameAsTypeMap; +}; + +export type NormDataMappings = Record; + +export type AutocompleteSuggestion = { + label: string; + value: string | null; +}; + +export type ColumnDesc = { + index: number; + value: T; + letter: string; +}; diff --git a/packages/core-types/settings.d.ts b/packages/core-types/settings.d.ts new file mode 100644 index 00000000..57b48323 --- /dev/null +++ b/packages/core-types/settings.d.ts @@ -0,0 +1,55 @@ +export type SparqlEndpoint = { + label?: string; + endpoint: string; + active: boolean; + auth?: { + username?: string; + password?: string; + token?: string; + }; + provider?: + | "allegro" + | "oxigraph" + | "worker" + | "blazegraph" + | "virtuoso" + | "qlever" + | "rest"; +}; +export type Features = { + enablePreview?: boolean; + enableDebug?: boolean; + enableBackdrop?: boolean; + enableStylizedCard?: boolean; +}; +export type OpenAIConfig = { + organization?: string; + apiKey?: string; +}; +export type GoogleDriveConfig = { + apiKey?: string; +}; +export type ExternalAuthorityConfig = { + kxp?: { + endpoint?: string; + baseURL?: string; + recordSchema?: string; + }; +}; +export type Settings = { + lockedEndpoint: boolean; + sparqlEndpoints: SparqlEndpoint[]; + + features: Features; + openai: OpenAIConfig; + googleDrive: GoogleDriveConfig; + externalAuthority: ExternalAuthorityConfig; +}; +export type UseLocalSettings = { + settingsOpen: boolean; + sparqlEndpoints: SparqlEndpoint[]; + setSparqlEndpoints: (endpoints: SparqlEndpoint[]) => void; + openSettings: () => void; + closeSettings: () => void; + getActiveEndpoint: () => SparqlEndpoint | undefined; +}; diff --git a/packages/core-utils/package.json b/packages/core-utils/package.json index 8d3329b2..6b5c7409 100644 --- a/packages/core-utils/package.json +++ b/packages/core-utils/package.json @@ -15,7 +15,6 @@ } }, "scripts": { - "build:package.json": "make-package-json", "build": "tsup", "dev": "tsup --watch", "lint": "eslint \"**/*.ts*\"", @@ -29,6 +28,7 @@ "@slub/edb-build-helper": "workspace:*", "@slub/edb-tsconfig": "workspace:*", "@slub/edb-tsup-config": "workspace:*", + "@slub/edb-core-types": "workspace:*", "@types/jest": "^29.5.12", "eslint-config-edb": "workspace:*", "typescript": "^5" diff --git a/packages/core-utils/src/camelCaseToTitleCase.ts b/packages/core-utils/src/camelCaseToTitleCase.ts new file mode 100644 index 00000000..dd79b7ce --- /dev/null +++ b/packages/core-utils/src/camelCaseToTitleCase.ts @@ -0,0 +1,5 @@ +export const camelCaseToTitleCase: (str: string) => string = (str: string) => { + return str.replace(/([A-Z])/g, " $1").replace(/^./, function (str) { + return str.toUpperCase(); + }); +}; diff --git a/packages/core-utils/src/envToSparqlEndpoint.ts b/packages/core-utils/src/envToSparqlEndpoint.ts new file mode 100644 index 00000000..0efef3a1 --- /dev/null +++ b/packages/core-utils/src/envToSparqlEndpoint.ts @@ -0,0 +1,43 @@ +import { SparqlEndpoint } from "@slub/edb-core-types"; + +const p = (key: string, prefix?: string) => (prefix ? `${prefix}_${key}` : key); + +/** + * Convert environment variables to a SparqlEndpoint object. + * + * environment variables: + * - SPARQL_ENDPOINT + * - SPARQL_ENDPOINT_LABEL + * - SPARQL_ENDPOINT_PROVIDER + * - SPARQL_ENDPOINT_USERNAME + * - SPARQL_ENDPOINT_PASSWORD + * - SPARQL_ENDPOINT_TOKEN + * + * @param env + * @param prefix if the environment variables are beeing prefixed (NEXT_PUBLIC_*, ...) + */ +export const envToSparqlEndpoint = ( + env: Record, + prefix?: string, +): SparqlEndpoint | undefined => { + const endpoint = env[p("SPARQL_ENDPOINT", prefix)]; + if (!endpoint) { + return; + } + const label = env[p("SPARQL_ENDPOINT_LABEL", prefix)] || "Custom"; + const provider = env[p("SPARQL_ENDPOINT_PROVIDER", prefix)] || "oxigraph"; + const username = env[p("SPARQL_ENDPOINT_USERNAME", prefix)]; + const password = env[p("SPARQL_ENDPOINT_PASSWORD", prefix)]; + const token = env[p("SPARQL_ENDPOINT_TOKEN", prefix)]; + return { + label, + endpoint, + active: true, + provider, + auth: { + username, + password, + token, + }, + } as SparqlEndpoint; +}; diff --git a/packages/core-utils/src/formatJSONResult.ts b/packages/core-utils/src/formatJSONResult.ts new file mode 100644 index 00000000..090b2770 --- /dev/null +++ b/packages/core-utils/src/formatJSONResult.ts @@ -0,0 +1,16 @@ +import { filterJSONLD } from "./filterJSONLD"; + +/** + * Used for logging and cli - simple helper function to format JSON results and optionally remove JSON-LD properties + * @param result some JSON object + * @param pretty whether to pretty print the JSON + * @param noJsonLD whether to remove JSON-LD properties + */ +export const formatJSONResult = ( + result: object, + pretty?: boolean, + noJsonLD?: boolean, +) => { + const res = noJsonLD ? filterJSONLD(result) : result; + return pretty ? JSON.stringify(res, null, 2) : JSON.stringify(res); +}; diff --git a/packages/core-utils/src/index.ts b/packages/core-utils/src/index.ts index 2bd31b84..bd4f5c14 100644 --- a/packages/core-utils/src/index.ts +++ b/packages/core-utils/src/index.ts @@ -11,3 +11,10 @@ export * from "./ellipsis"; export * from "./parseMarkdownLink"; export * from "./filterJSONLD"; export * from "./numeric2JSDate"; +export * from "./permissions"; +export * from "./envToSparqlEndpoint"; +export * from "./camelCaseToTitleCase"; +export * from "./index2letter"; +export * from "./makeColumnDesc"; +export * from "./formatJSONResult"; +export * from "./replaceJSONLD"; diff --git a/packages/core-utils/src/index2letter.ts b/packages/core-utils/src/index2letter.ts new file mode 100644 index 00000000..9cdfaa10 --- /dev/null +++ b/packages/core-utils/src/index2letter.ts @@ -0,0 +1,7 @@ +export const index2letter = (index: number): string => { + const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + const mod = index % alphabet.length; + const rest = (index - mod) / alphabet.length; + const letter = alphabet[mod]; + return rest > 0 ? index2letter(rest) + letter : letter; +}; diff --git a/packages/core-utils/src/makeColumnDesc.ts b/packages/core-utils/src/makeColumnDesc.ts new file mode 100644 index 00000000..482aa7c8 --- /dev/null +++ b/packages/core-utils/src/makeColumnDesc.ts @@ -0,0 +1,8 @@ +import { ColumnDesc } from "@slub/edb-core-types"; +import { index2letter } from "./index2letter"; +export const makeColumnDesc: (cells: T[]) => ColumnDesc[] = (cells) => + cells.map((value, index) => ({ + index, + value, + letter: index2letter(index), + })); diff --git a/packages/core-utils/src/permissions.ts b/packages/core-utils/src/permissions.ts new file mode 100644 index 00000000..baf2420f --- /dev/null +++ b/packages/core-utils/src/permissions.ts @@ -0,0 +1,18 @@ +import { Permission } from "@slub/edb-core-types"; + +export const fullPermission: Permission = { + view: true, + edit: true, +}; + +export const viewerPermission: Permission = { + view: true, + edit: false, +}; + +export const noPermission: Permission = { + view: false, + edit: false, +}; + +export const defaultPermission = viewerPermission; diff --git a/packages/core-utils/src/replaceJSONLD.ts b/packages/core-utils/src/replaceJSONLD.ts new file mode 100644 index 00000000..90d44fa3 --- /dev/null +++ b/packages/core-utils/src/replaceJSONLD.ts @@ -0,0 +1,32 @@ +/** + * will recursively look for @context, @type, @id and replace them with the provided string + * @param obj the object to replace the values in + * @param replacement the string to replace the values with (default: "_") + * @param visited a set of already visited objects to avoid infinite recursion (in doubt leave empty) + */ +export const replaceJSONLD = ( + obj: any, + replacement: string = "_", + visited = new WeakSet(), +): any => { + if (obj && typeof obj === "object") { + if (visited.has(obj)) { + return obj; // Avoid infinite recursion by returning already visited objects + } + if (Array.isArray(obj)) { + return obj.map((item) => replaceJSONLD(item, replacement, visited)); + } + visited.add(obj); + + return Object.fromEntries( + Object.entries(obj).map(([key, value]: [string, any]) => { + if (key.startsWith("@")) { + return [key.replace("@", replacement), value]; + } else { + return [key, replaceJSONLD(value, replacement, visited)]; + } + }), + ); + } + return obj; +}; diff --git a/packages/core-utils/src/specialDate.ts b/packages/core-utils/src/specialDate.ts index 643ce14a..3ac9f316 100644 --- a/packages/core-utils/src/specialDate.ts +++ b/packages/core-utils/src/specialDate.ts @@ -78,3 +78,34 @@ export const getPaddedDate = (date: Date) => { const day = leftpad(date.getDate(), 2); return `${year}${month}${day}`; }; + +/** + * convert a number to a string with a given length, pad it with zeros + * @param date the date as number between 0 and 99999999 + * @param part the part of the date to extract ("day", "month", or "year") + */ +export const getDatePartAsString = ( + date: number, + part: "day" | "month" | "year", +) => { + const value = getDatePart(date, part); + if (value === 0) return ""; + const maxLength = part === "year" ? 4 : 2; + return leftpad(value, maxLength); +}; + +/** + * convert year, month, day to a number + * @param year + * @param month + * @param day + * @returns + */ +export const makeSpecialDate = ( + year: number, + month?: number | undefined, + day?: number | undefined, +) => { + const specialDateString = `${year}${month ? leftpad(month, 2) : "00"}${day ? leftpad(day, 2) : "00"}`; + return Number(specialDateString); +}; diff --git a/packages/core-utils/tsup.config.js b/packages/core-utils/tsup.config.js index 3dd890ed..85b8dcc3 100644 --- a/packages/core-utils/tsup.config.js +++ b/packages/core-utils/tsup.config.js @@ -1,3 +1,5 @@ -import config from "@slub/edb-tsup-config/tsup.config.js"; +import { makeConfigWithExternals } from "@slub/edb-tsup-config/tsup.config.js"; +import pkg from "./package.json"; +const config = makeConfigWithExternals(pkg); export default config; diff --git a/packages/data-mapping/package.json b/packages/data-mapping/package.json new file mode 100644 index 00000000..9e2128c7 --- /dev/null +++ b/packages/data-mapping/package.json @@ -0,0 +1,35 @@ +{ + "name": "@slub/edb-data-mapping", + "version": "0.1.0", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "type": "module", + "license": "MIT", + "scripts": { + "build": "tsup", + "dev": "tsup --watch", + "lint": "eslint \"**/*.ts*\"", + "lint-fix": "eslint --fix \"**/*.ts*\"", + "test": "jest", + "test:watch": "jest --watch --color", + "test:coverage": "jest --coverage" + }, + "devDependencies": { + "@slub/edb-build-helper": "workspace:*", + "@types/jsonpath": "^0.2.4", + "dayjs": "^1.11.11" + }, + "peerDependencies": { + "ajv": ">8.12", + "dayjs": ">1" + }, + "dependencies": { + "@slub/edb-core-utils": "workspace:*", + "@slub/edb-core-types": "workspace:*", + "@slub/edb-global-types": "workspace:*", + "lodash-es": "^4.17.21", + "jsonpath": "^1.1.1", + "json-schema": "^0.4.0", + "dot": "2.0.0-beta.1" + } +} diff --git a/packages/data-mapping/src/index.ts b/packages/data-mapping/src/index.ts new file mode 100644 index 00000000..7ffdeb31 --- /dev/null +++ b/packages/data-mapping/src/index.ts @@ -0,0 +1,8 @@ +export * from "./mapByConfig"; +export * from "./matchBased2DeclarativeFlatMapping"; +export * from "./mappingStrategies"; +export * from "./simpleFieldExtractor"; +export * from "./types"; +export * from "./mapByConfigFlat"; +export * from "./mapFromFlatResource"; +export * from "./makeCreateDeeperContextFn"; diff --git a/packages/data-mapping/src/makeCreateDeeperContextFn.ts b/packages/data-mapping/src/makeCreateDeeperContextFn.ts new file mode 100644 index 00000000..4f33179e --- /dev/null +++ b/packages/data-mapping/src/makeCreateDeeperContextFn.ts @@ -0,0 +1,46 @@ +import { StrategyContext } from "./mappingStrategies"; + +/** + * Create a logger for a specific path + * + * the logger will log to the console if disableLogging is false and will log the path before the message + * + * @param path + * @param disableLogging + */ +export const createLogger = (path: string[], disableLogging: boolean) => ({ + log: (message: string) => { + if (!disableLogging) { + console.log(path.join("/")); + console.log(`\t${message}`); + } + }, + warn: (message: string) => { + if (!disableLogging) { + console.warn(path.join("/")); + console.warn(`\t${message}`); + } + }, + error: (message: string) => { + if (!disableLogging) { + console.error(message); + } + }, +}); + +/** + * Create a function to create a deeper context. A deeper context is a context with a longer path. Deep, because mapping + * requires for recursive data mapping and entity generation. + * + * @param disableLogging + */ +export const makeCreateDeeperContextFn = + (disableLogging: boolean) => + (context: StrategyContext, pathElement: string) => { + const path = [...context.path, pathElement]; + return { + ...context, + path, + logger: createLogger(path, disableLogging), + }; + }; diff --git a/packages/data-mapping/src/mapByConfig.ts b/packages/data-mapping/src/mapByConfig.ts new file mode 100644 index 00000000..71ec76f9 --- /dev/null +++ b/packages/data-mapping/src/mapByConfig.ts @@ -0,0 +1,114 @@ +import Ajv from "ajv"; +import cloneDeep from "lodash-es/cloneDeep"; +import get from "lodash-es/get"; +import isNil from "lodash-es/isNil"; +import set from "lodash-es/set"; +import jsonpath from "jsonpath"; + +import { + DeclarativeMappings, + StrategyContext, + strategyFunctionMap, +} from "./mappingStrategies"; + +/** + * Get value from sourceData via a sourcePath which can be either a string or an array of strings + * if sourcePath starts with $ it is treated as a jsonpath {@link https://goessner.net/articles/JsonPath/}, + * that are able to map complex structures just like XPath expressions in XML + * {@example $.store.book[*].title will return all titles of books in store} + * otherwise it is treated as a lodash path {@link https://lodash.com/docs/4.17.15#get} + * @param sourceData + * @param sourcePath + */ +const getViaSourcePath = ( + sourceData: any, + sourcePath: string[] | string, +): any => { + if (Array.isArray(sourcePath)) { + return get(sourceData, sourcePath); + } + if (typeof sourcePath === "string") { + if (sourcePath.startsWith("$")) { + return jsonpath.query(sourceData, sourcePath); + } + return get(sourceData, sourcePath); + } +}; + +/** + * Map sourceData to targetData by a declarative mappingConfig + * the initially passed seedData is used as a base for the new data + * and won't be mutated + * + * Look at the docs for more information on certain mapping strategies + * for the case that no strategy is defined the value will be taken as is + * + * @param sourceData + * @param seedData + * @param mappingConfig + * @param strategyContext + */ +export const mapByConfig = async ( + sourceData: Record, + seedData: any, + mappingConfig: DeclarativeMappings, + strategyContext: StrategyContext, +): Promise => { + const newData = cloneDeep(seedData); //clone targetData to not mutate it accidentally + const ajv = new Ajv(); + for (const { source, target, mapping } of mappingConfig) { + const { path: sourcePath, expectedSchema } = source; + const { path: targetPath } = target; + const { logger } = strategyContext; + const hasSourcePath = source?.path && source.path.length > 0; + logger.log( + `Mapping ${sourcePath} to ${targetPath} using ${mapping?.strategy?.id || "default strategy"}`, + ); + const sourceValue = hasSourcePath + ? getViaSourcePath(sourceData, sourcePath) + : sourceData; + if (isNil(sourceValue)) continue; + if (expectedSchema && !ajv.validate(expectedSchema, sourceValue)) { + if (strategyContext.options?.strictCheckTargetData) + throw new Error( + `Value does not match expected schema ${JSON.stringify( + expectedSchema, + )}`, + ); + logger.warn( + `Value does not match expected schema ${JSON.stringify( + expectedSchema, + )}`, + ); + } else { + if (!mapping?.strategy) { + //take value as is if no strategy is defined + set(newData, targetPath, sourceValue); + } else { + const mappingFunction = strategyFunctionMap[mapping.strategy.id]; + if (typeof mappingFunction !== "function") { + throw new Error(`Strategy ${mapping.strategy.id} is not implemented`); + } + const strategyOptions = (mapping.strategy as any).options; + const value = await mappingFunction( + sourceValue, + get(newData, targetPath), + strategyOptions, + strategyContext.createDeeperContext( + strategyContext, + `${mapping.strategy.id}_${targetPath}`, + mappingConfig, + ), + ); + if (!isNil(value)) { + set(newData, targetPath, value); + } else { + logger.warn( + `Strategy ${mapping.strategy.id} returned undefined for ${sourceValue}`, + ); + } + } + } + } + return newData; +}; diff --git a/packages/data-mapping/src/mapByConfigFlat.ts b/packages/data-mapping/src/mapByConfigFlat.ts new file mode 100644 index 00000000..492d5834 --- /dev/null +++ b/packages/data-mapping/src/mapByConfigFlat.ts @@ -0,0 +1,91 @@ +import { + DeclarativeFlatMappings, + StrategyContext, + strategyFunctionMap, +} from "./mappingStrategies"; +import { MappingOptions } from "./types"; +import cloneDeep from "lodash-es/cloneDeep"; +import { filterUndefOrNull } from "@slub/edb-core-utils"; +import set from "lodash-es/set"; +import get from "lodash-es/get"; +import isNil from "lodash-es/isNil"; + +/** + * Get values from accessorFn via columnPaths, + * @param accessorFn + * @param columnPaths + */ +const getViaColumnPaths = ( + accessorFn: (col: number | string) => any, + columnPaths: (string | number)[], +): any => columnPaths.map((path) => accessorFn(path)); +export const mapByConfigFlat = async ( + accessorFn: (col: number | string) => any, + seedData: any, + mappingConfig: DeclarativeFlatMappings, + strategyContext: StrategyContext, + options: MappingOptions = {}, +): Promise => { + const newData = cloneDeep(seedData); //clone targetData to not mutate it accidentally + const { logger } = strategyContext; + for (const { source, target, mapping } of mappingConfig) { + try { + const { path: targetPath } = target; + if (!source?.columns || source.columns.length === 0) + throw new Error( + `No source path defined for mapping ${JSON.stringify(mapping)}`, + ); + const isList = source.columns.length === 1 && source.columns[0]; + if (!mapping?.strategy) { + //take value as is if no strategy is defined + const sourceValue = filterUndefOrNull( + getViaColumnPaths(accessorFn, source.columns), + ); + if (sourceValue.length === 0) continue; + if (isList) { + set(newData, targetPath, sourceValue[0]); + } else { + set(newData, targetPath, sourceValue); + } + } else { + const mappingFunction = strategyFunctionMap[mapping.strategy.id]; + if (typeof mappingFunction !== "function") { + throw new Error(`Strategy ${mapping.strategy.id} is not implemented`); + } + const strategyOptions = (mapping.strategy as any).options; + let value: any; + if (isList) { + value = await mappingFunction( + getViaColumnPaths(accessorFn, source.columns)[0], + get(newData, targetPath), + strategyOptions, + strategyContext.createDeeperContext( + strategyContext, + `${mapping.strategy.id}_${targetPath}`, + mappingConfig, + ), + ); + } else { + value = await mappingFunction( + getViaColumnPaths(accessorFn, source.columns), + get(newData, targetPath), + strategyOptions, + strategyContext.createDeeperContext( + strategyContext, + `${mapping.strategy.id}_${targetPath}`, + mappingConfig, + ), + ); + if (Array.isArray(value)) value = filterUndefOrNull(value); + } + if (!isNil(value)) set(newData, targetPath, value); + } + } catch (e) { + if (options.throwOnAttributeError) throw e; + logger.error( + `Error while mapping source.columns: ${JSON.stringify(source.columns)} to target.path ${target.path} \n ${e}`, + ); + } + } + return newData; +}; diff --git a/packages/data-mapping/src/mapFromFlatResource.ts b/packages/data-mapping/src/mapFromFlatResource.ts new file mode 100644 index 00000000..78ea5fcc --- /dev/null +++ b/packages/data-mapping/src/mapFromFlatResource.ts @@ -0,0 +1,71 @@ +import { makeColumnDesc } from "@slub/edb-core-utils"; +import { + DeclarativeMatchBasedFlatMappings, + matchBased2DeclarativeFlatMappings, +} from "./matchBased2DeclarativeFlatMapping"; +import { DeclarativeFlatMappings, StrategyContext } from "./mappingStrategies"; +import { ProcessFlatResourceFn } from "./types"; +import { mapByConfigFlat } from "./mapByConfigFlat"; + +/** + * Map data from a flat resource (e.g. CSV) to entities. + * + * @param typeIRI the type IRI of the entities each record represents + * @param matchBasedFlatMappings the flat mapping declarations + * @param strategyContext + * @param processFlatResourceFn the function to process the flat resource + * @param newIRI a function to generate a new IRI for each record, optionally based on the record + * @param onMappedData a function to handle the mapped data + * @param amount the amount of records to process from the resource + * @param offset the offset to start processing from + */ +export const mapFromFlatResource = async ( + typeIRI: string, + matchBasedFlatMappings: DeclarativeMatchBasedFlatMappings, + strategyContext: StrategyContext, + processFlatResourceFn: ProcessFlatResourceFn, + newIRI: (record: string[]) => string, + onMappedData: ( + entityIRI: string, + mappedData: any, + originalRecord: string[], + index: number, + ) => Promise, + amount?: number, + offset?: number, +) => { + let flatMappings: DeclarativeFlatMappings | null = null; + const { logger } = strategyContext; + await processFlatResourceFn( + async (header) => { + const columnDesc = makeColumnDesc(header); + flatMappings = matchBased2DeclarativeFlatMappings( + columnDesc, + matchBasedFlatMappings, + { throwOnMappingError: false }, + ); + return; + }, + async (record, index) => { + if (!flatMappings) { + throw new Error("No mapping found"); + } + try { + const mappedData = await mapByConfigFlat( + (colIndex) => record[colIndex], + { + "@type": typeIRI, + "@id": newIRI(record), + }, + flatMappings, + strategyContext, + ); + await onMappedData(mappedData["@id"], mappedData, record, index); + } catch (e) { + logger.error(`Error while mapping record ${index} \n ${e}`); + } + }, + amount, + offset, + ); +}; diff --git a/apps/exhibition-live/components/utils/mapping/mappingStrategies.ts b/packages/data-mapping/src/mappingStrategies.ts similarity index 57% rename from apps/exhibition-live/components/utils/mapping/mappingStrategies.ts rename to packages/data-mapping/src/mappingStrategies.ts index e46fc41f..61978740 100644 --- a/apps/exhibition-live/components/utils/mapping/mappingStrategies.ts +++ b/packages/data-mapping/src/mappingStrategies.ts @@ -1,18 +1,18 @@ -import { JsonSchema } from "@jsonforms/core"; import dayjs from "dayjs"; import customParseFormat from "dayjs/plugin/customParseFormat"; import { mapByConfig } from "./mapByConfig"; -import isNil from "lodash/isNil"; -import { findEntityWithinLobidByIRI } from "../lobid/findEntityWithinLobid"; +import isNil from "lodash-es/isNil"; +import set from "lodash-es/set"; +import get from "lodash-es/get"; +import { getPaddedDate, makeSpecialDate } from "@slub/edb-core-utils"; import { - declarativeMappings, - primaryFields, - typeIRItoTypeName, -} from "../../config"; -import set from "lodash/set"; -import get from "lodash/get"; -import { getPaddedDate } from "@slub/edb-core-utils"; + IRIToStringFn, + NormDataMappings, + PrimaryFieldDeclaration, +} from "@slub/edb-core-types"; +import { JSONSchema7 } from "json-schema"; +import { isNaN } from "lodash-es"; dayjs.extend(customParseFormat); @@ -20,6 +20,23 @@ interface Strategy { id: string; } +export type AuthorityConfiguration = { + authorityIRI: string; + getEntityByIRI: (iri: string) => Promise; +}; + +export type Logger = { + log: (message: string) => void; + warn: (message: string) => void; + error: (message: string) => void; +}; + +export type CreateDeeperContextFn = ( + strategy: StrategyContext, + pathElement: string, + currentMapping?: DeclarativeMappings | DeclarativeFlatMappings, +) => StrategyContext; + export type StrategyContext = { getPrimaryIRIBySecondaryIRI: ( secondaryIRI: string, @@ -30,13 +47,22 @@ export type StrategyContext = { label: string, typeIRI: string, ) => Promise; + authorityAccess?: Record; authorityIRI: string; newIRI: (typeIRI: string) => string; + onNewDocument?: (document: any) => Promise; options?: { strictCheckSourceData?: boolean; strictCheckTargetData?: boolean; }; mappingTable?: DeclarativeMapping; + currentMapping?: DeclarativeMappings; + primaryFields: PrimaryFieldDeclaration; + typeIRItoTypeName: IRIToStringFn; + normDataMappings: NormDataMappings; + path: string[]; + logger: Logger; + createDeeperContext: CreateDeeperContextFn; }; export type StrategyFunction = ( @@ -82,6 +108,29 @@ type TakeFirstStrategy = Strategy & { export const takeFirst = (sourceData: any[], _targetData: any): any => sourceData[0]; +type WithDotTemplateStrategy = Strategy & { + id: "withDotTemplate"; + options?: { + single?: boolean; + template: string; + }; +}; + +export const withDotTemplate = ( + sourceData: any | any[], + _targetData: any, + options?: WithDotTemplateStrategy["options"], +): any => { + const sourceD = Array.isArray(sourceData) ? sourceData : [sourceData]; + const { template } = options || {}; + let result = []; + for (const s of sourceD) { + result.push(template.replace("{{value}}", s)); + if (options?.single) return result[0]; + } + return result; +}; + type AppendStrategy = Strategy & { id: "append"; options?: { @@ -127,6 +176,7 @@ type AuthorityFieldInformation = { type CreateEntityWithAuthoritativeLink = Strategy & { id: "createEntityWithAuthoritativeLink"; options?: { + single?: boolean; typeIRI?: string; typeName?: string; mainProperty: { @@ -151,46 +201,48 @@ export const createEntityWithAuthoritativeLink = async ( context?: StrategyContext, ): Promise => { if (!context) throw new Error("No context provided"); - const { typeIRI, mainProperty, authorityFields } = options || {}; + const { + searchEntityByLabel, + getPrimaryIRIBySecondaryIRI, + authorityIRI, + newIRI, + primaryFields, + typeIRItoTypeName, + normDataMappings, + authorityAccess, + createDeeperContext, + logger, + onNewDocument, + } = context; + const { typeIRI, mainProperty, authorityFields, single } = options || {}; if (!Array.isArray(sourceData)) throw new Error("Source data is not an array"); const amount = authorityFields.length + 1; if (sourceData.length % amount !== 0) - console.warn( + logger.warn( `Source data length ${sourceData.length} is not a multiple of ${amount}`, ); - /* - throw new Error( - `Source data length ${sourceData.length} is not a multiple of ${amount}`, - );*/ const groupedSourceData = []; for (let i = 0; i < sourceData.length; i += amount) { groupedSourceData.push(sourceData.slice(i, i + amount)); } - console.log(groupedSourceData); - - const { - searchEntityByLabel, - getPrimaryIRIBySecondaryIRI, - authorityIRI, - newIRI, - } = context; - const sourceDataArray = sourceData; const newDataElements = []; for (const sourceDataGroupElement of groupedSourceData) { const sourceDataElement = sourceDataGroupElement[0]; if (authorityFields.length > 1) { - console.warn( + logger.warn( "only one authority field is supported at the moment. Will use the first one.", ); } const authorityOptions = authorityFields[0]; const authIRI = authorityOptions.authorityIRI || authorityIRI; const authLinkPrefix = authorityOptions.authorityLinkPrefix || ""; - const sourceDataAuthority = sourceDataGroupElement[1]; - const secondaryIRI = + const authAccess = authorityAccess?.[authIRI]; + const sourceDataAuthority = sourceDataGroupElement[authorityOptions.offset]; + const typeName = typeIRItoTypeName(typeIRI); + let secondaryIRI = typeof sourceDataAuthority === "string" && sourceDataAuthority.trim().length > 0 ? `${authLinkPrefix}${sourceDataAuthority}` @@ -199,66 +251,148 @@ export const createEntityWithAuthoritativeLink = async ( let primaryIRI: string | null = null; if (secondaryIRI) { - console.log(`will look for ${secondaryIRI} within own database`); + logger.log(`will look for ${secondaryIRI} within own database`); primaryIRI = await getPrimaryIRIBySecondaryIRI( secondaryIRI, authIRI, typeIRI, ); - if (primaryIRI) { - console.log( - `found ${secondaryIRI} as ${primaryIRI} within own database`, - ); - } } else if (sourceDataLabel) { + logger.log( + `will look for "${sourceDataLabel}" type ${typeName} within own database by label`, + ); primaryIRI = await searchEntityByLabel(sourceDataLabel, typeIRI); } - const typeName = typeIRItoTypeName(typeIRI); + if (primaryIRI) { + logger.log(`found ${secondaryIRI} as ${primaryIRI} within own database`); + newDataElements.push({ + "@id": primaryIRI, + }); + continue; + } + const primaryField = primaryFields[typeName]; const labelField = primaryField?.label || "label"; let targetData: any = {}; - if (!primaryIRI && secondaryIRI) { - console.log("not yet implemented look form id within external database"); - //TODO: we will hardcode lobid search here but this should be taken out of the context and linked with properties from options - const lobidData = await findEntityWithinLobidByIRI(secondaryIRI); - if (lobidData) { - const mappingConfig = declarativeMappings[typeName]; - if (!mappingConfig) { - console.warn(`no mapping config for ${typeName}`); - } else { - try { - const dataFromGND = await mapByConfig( - lobidData, - {}, - mappingConfig, - context, - ); - const inject = { - "@id": newIRI(typeIRI || ""), - "@type": typeIRI, - lastNormUpdate: new Date().toISOString(), - }; - targetData = { ...dataFromGND, ...inject }; - } catch (e) { - console.error(e); + if (secondaryIRI && authAccess) { + logger.log( + `will look for ${secondaryIRI} of type ${typeName} within external database`, + ); + + let normData = null; + try { + normData = await authAccess.getEntityByIRI(secondaryIRI); + } catch (e) { + logger.error( + `error while fetching ${secondaryIRI} from external database - maybe the entry does not exist? \n ${e}`, + ); + } + if (!normData) { + logger.warn(`no data found for ${secondaryIRI}`); + continue; + } + + let mappingConfig = normDataMappings?.[authIRI]?.mapping?.[typeName]; + let authorityIRI = authIRI; + + //JUst a quick and dirty hack to use wikidata instead of the default authority + if (Array.isArray(normData?.sameAs)) { + const wikidataEntry = normData.sameAs.find(({ id }: { id: string }) => + id.startsWith("http://www.wikidata.org/entity/"), + ); + const wikidataMappingConfig = + normDataMappings?.["http://www.wikidata.org"]?.mapping?.[typeName]; + if (wikidataEntry && wikidataMappingConfig) { + const wikidataIRI = wikidataEntry.id; + const wdAuthAccess = authorityAccess?.["http://www.wikidata.org"]; + if (wdAuthAccess) { + try { + normData = await wdAuthAccess.getEntityByIRI(wikidataIRI); + mappingConfig = wikidataMappingConfig; + authorityIRI = "http://www.wikidata.org"; + logger.log( + `found wikidata entry for ${secondaryIRI} at ${wikidataIRI}, will map this entry`, + ); + secondaryIRI = wikidataIRI; + + primaryIRI = await getPrimaryIRIBySecondaryIRI( + secondaryIRI, + authorityIRI, + typeIRI, + ); + } catch (e) { + logger.error( + `error while fetching ${wikidataIRI} from external database - maybe the entry does not exist? \n ${e}`, + ); + } } } - if (!targetData) { - targetData = { + } + if ((!mappingConfig || !normData) && !primaryIRI) { + logger.warn( + `no mapping config for ${typeName} or no normData in ${authIRI}, cannot convert to local data model`, + ); + } else if (primaryIRI) { + logger.log( + `found ${secondaryIRI} as ${primaryIRI} within internal database`, + ); + newDataElements.push({ + "@id": primaryIRI, + }); + continue; + } else { + logger.log("mapping authority entry to local data model"); + try { + const data = await mapByConfig( + normData, + {}, + mappingConfig, + createDeeperContext( + { + ...context, + authorityIRI, + }, + `createEntityWithAuthoritativeLink_${typeName}`, + mappingConfig, + ), + ); + const inject = { "@id": newIRI(typeIRI || ""), "@type": typeIRI, - [labelField]: sourceDataLabel, - __draft: true, + lastNormUpdate: new Date().toISOString(), + idAuthority: { + authority: authorityIRI, + id: secondaryIRI, + }, }; + targetData = { ...data, ...inject }; + } catch (e) { + logger.error( + `error mapping authority entry to local data model \n ${e}`, + ); } - newDataElements.push(targetData); - } else { - newDataElements.push({ - "@id": primaryIRI, - }); } + if (!targetData) { + logger.log( + `no data found for ${secondaryIRI}, will create a new entity of type ${typeIRI} with label ${sourceDataLabel}`, + ); + targetData = { + "@id": newIRI(typeIRI || ""), + "@type": typeIRI, + [labelField]: sourceDataLabel, + __draft: true, + }; + } + + const newEntity = onNewDocument + ? await onNewDocument(targetData) + : targetData; + + newDataElements.push(newEntity); } + + if (single) return newDataElements[0]; } return newDataElements; }; @@ -287,7 +421,7 @@ export const createEntityWithReificationFromString = async ( ): Promise => { if (!context) throw new Error("No context provided"); const { typeIRI, mainProperty, statementProperties } = options || {}; - const { newIRI } = context; + const { newIRI, onNewDocument } = context; if (!Array.isArray(sourceData)) throw new Error("Source data is not an array"); const newDataElements = []; @@ -338,8 +472,8 @@ export const createEntityWithReificationFromString = async ( for (const statementProperty of statementProperties) { const sourceDataElement = - typeof mainProperty.offset === "number" - ? sourceDataElements[mainProperty.offset] + typeof statementProperty.offset === "number" + ? sourceDataElements[statementProperty.offset] : sourceDataElements; if ( typeof sourceDataElement !== "string" || @@ -368,12 +502,17 @@ export const createEntityWithReificationFromString = async ( } newDataElements.push(newData); } - return newDataElements.map((newData) => ({ - "@id": newIRI(typeIRI || ""), - "@type": typeIRI, - __draft: true, - ...newData, - })); + return await Promise.all( + newDataElements.map(async (newData) => { + const newEntity = { + "@id": newIRI(typeIRI || ""), + "@type": typeIRI, + __draft: true, + ...newData, + }; + return onNewDocument ? await onNewDocument(newEntity) : newEntity; + }), + ); }; type CreateEntityFromStringStrategy = Strategy & { @@ -384,16 +523,22 @@ type CreateEntityFromStringStrategy = Strategy & { }; }; -type CreateEntityStrategy = Strategy & { +export type MappingID = string; + +export type FromEntity = DeclarativeMappings | MappingID | "self"; + +export type SubFieldMappingConnection = { + fromSelf?: DeclarativeMappings; + fromEntity?: FromEntity; +}; + +export type CreateEntityStrategy = Strategy & { id: "createEntity"; options?: { typeIRI?: string; typeName?: string; single?: boolean; - subFieldMapping: { - fromSelf?: DeclarativeMappings; - fromEntity?: DeclarativeMappings; - }; + subFieldMapping: SubFieldMappingConnection; }; }; @@ -405,7 +550,13 @@ export const createEntityFromString = async ( ): Promise => { if (!context) throw new Error("No context provided"); const { typeIRI } = options || {}; - const { searchEntityByLabel, newIRI } = context; + const { + searchEntityByLabel, + newIRI, + typeIRItoTypeName, + primaryFields, + onNewDocument, + } = context; const isArray = Array.isArray(sourceData); const sourceDataArray = isArray ? sourceData : [sourceData]; const newDataElements = []; @@ -431,7 +582,9 @@ export const createEntityFromString = async ( [labelField]: trimmedSourceDataElement, __draft: true, }; - newDataElements.push(targetData); + newDataElements.push( + onNewDocument ? await onNewDocument(targetData) : targetData, + ); } else { newDataElements.push({ "@id": primaryIRI, @@ -451,11 +604,23 @@ export const createEntity = async ( const { typeIRI, subFieldMapping, single } = options || {}; const isArray = Array.isArray(sourceData); const sourceDataArray = isArray ? sourceData : [sourceData]; - const { getPrimaryIRIBySecondaryIRI, newIRI, authorityIRI } = context; + const { + getPrimaryIRIBySecondaryIRI, + newIRI, + logger, + createDeeperContext, + onNewDocument, + normDataMappings, + authorityAccess, + } = context; + let authorityIRI = context.authorityIRI; + const authAccess = authorityAccess?.[authorityIRI]; + const mappingTable = normDataMappings?.[authorityIRI]?.mapping; const newDataElements = []; + for (const sourceDataElement of sourceDataArray) { const authorityEntryIRI = sourceDataElement.id; - const primaryIRI = await getPrimaryIRIBySecondaryIRI( + let primaryIRI = await getPrimaryIRIBySecondaryIRI( authorityEntryIRI, authorityIRI, typeIRI, @@ -466,27 +631,113 @@ export const createEntity = async ( "@type": typeIRI, __draft: true, }; - if (options?.typeName && context.mappingTable?.[options.typeName]) { - const mapping = context.mappingTable[options.typeName]; - const fullData = await findEntityWithinLobidByIRI(sourceDataElement.id); - if (fullData) { + let secondaryIRI = authorityEntryIRI; + + const typeName: string | undefined = options?.typeName; + if (typeName && mappingTable?.[typeName] && authAccess) { + let mappingConfig = mappingTable[typeName]; + let normData = await authAccess.getEntityByIRI(secondaryIRI); + //Just a quick and dirty hack to use wikidata instead of the default authority + if (Array.isArray(normData?.sameAs)) { + const wikidataEntry = normData.sameAs.find(({ id }: { id: string }) => + id.startsWith("http://www.wikidata.org/entity/"), + ); + const wikidataMappingConfig = + normDataMappings?.["http://www.wikidata.org"]?.mapping?.[typeName]; + if (wikidataEntry && wikidataMappingConfig) { + const wikidataIRI = wikidataEntry.id; + const wdAuthAccess = authorityAccess?.["http://www.wikidata.org"]; + if (wdAuthAccess) { + try { + normData = await wdAuthAccess.getEntityByIRI(wikidataIRI); + mappingConfig = wikidataMappingConfig; + authorityIRI = "http://www.wikidata.org"; + logger.log( + `found wikidata entry for ${secondaryIRI} at ${wikidataIRI}, will map this entry`, + ); + secondaryIRI = wikidataIRI; + primaryIRI = await getPrimaryIRIBySecondaryIRI( + secondaryIRI, + authorityIRI, + typeIRI, + ); + } catch (e) { + logger.error( + `error while fetching ${wikidataIRI} from external database - maybe the entry does not exist? \n ${e}`, + ); + } + } + } + } + + if (normData && !primaryIRI) { + logger.log( + `mapping authority entry (${secondaryIRI}) to local data model of type ${typeName} (${authorityIRI})`, + ); const mappedData = await mapByConfig( - fullData, + normData, targetData, - mapping, - context, + mappingConfig, + createDeeperContext( + { + ...context, + authorityIRI, + }, + `createEntity_${typeName}`, + mappingConfig, + ), + ); + + const result = onNewDocument + ? await onNewDocument(mappedData) + : mappedData; + if (!isArray || single) { + return result; + } + newDataElements.push(result); + } else if (primaryIRI) { + logger.log( + `found ${secondaryIRI} as ${primaryIRI} within internal database`, ); - newDataElements.push(mappedData); + newDataElements.push({ + "@id": primaryIRI, + }); } } else if (subFieldMapping) { - newDataElements.push( - await mapByConfig( + logger.log( + `mapping authority entry (${sourceDataElement.id}) to local data model of type ${typeName} with the given subfield mapping`, + ); + let subFieldMappingDeclaration = subFieldMapping.fromEntity; + if (subFieldMapping.fromEntity === "self") { + subFieldMappingDeclaration = context.currentMapping; + } else if (typeof subFieldMapping.fromEntity === "string") { + subFieldMappingDeclaration = + context.mappingTable?.[subFieldMapping.fromEntity]; + } + + if (!Array.isArray(subFieldMappingDeclaration)) { + logger.error( + "subFieldMappingDeclaration is not an array, either the mapping id does not exist or the mapping is not an array", + ); + } else { + const newEntity = await mapByConfig( sourceDataElement, targetData, - subFieldMapping.fromEntity || [], - context, - ), - ); + subFieldMappingDeclaration, + createDeeperContext( + context, + `createEntity_${typeName}`, + subFieldMappingDeclaration, + ), + ); + const result = onNewDocument + ? await onNewDocument(newEntity) + : newEntity; + if (!isArray || single) { + return result; + } + newDataElements.push(result); + } } } else { newDataElements.push({ @@ -494,6 +745,7 @@ export const createEntity = async ( }); } } + return isArray && !single ? newDataElements : newDataElements[0]; }; @@ -632,6 +884,45 @@ export const dateRangeStringToSpecialInt = ( ); }; +type ArrayToAdbDateStrategy = Strategy & { + id: "arrayToAdbDate"; + options?: { + offset?: number; + }; +}; + +export const arrayToAdbDate = ( + sourceData: any[], + _targetData: any, + options?: ArrayToAdbDateStrategy["options"], + context?: StrategyContext, +): { + dateValue: number; + dateModifier: number; +} => { + const { logger } = context || {}; + const { offset = 0 } = options || {}; + if (sourceData.length < offset + 3) + throw new Error( + `Not enough data (${sourceData.length}) to convert to date`, + ); + + const day = Number(sourceData[offset]); + const month = Number(sourceData[offset + 1] || "0"); + const year = Number(sourceData[offset + 2] || "0"); + const dateValue = makeSpecialDate( + isNaN(year) ? 0 : year, + isNaN(month) ? 0 : month, + isNaN(day) ? 0 : day, + ); + logger.log(`Converted date ${dateValue} from ${sourceData}`); + + return { + dateValue: Number(dateValue), + dateModifier: 0, + }; +}; + export type AnyStrategy = | ConcatenateStrategy | TakeFirstStrategy @@ -639,11 +930,14 @@ export type AnyStrategy = | CreateEntityStrategy | CreateEntityFromStringStrategy | CreateEntityWithReificationFromString + | CreateEntityWithAuthoritativeLink | DateRangeStringToSpecialInt | DateStringToSpecialInt | ExistsStrategy | ConstantStrategy - | SplitStrategy; + | SplitStrategy + | WithDotTemplateStrategy + | ArrayToAdbDateStrategy; export type AnyFlatStrategy = | ConcatenateStrategy @@ -653,11 +947,13 @@ export type AnyFlatStrategy = | CreateEntityWithReificationFromString | CreateEntityWithAuthoritativeLink | DateArrayToSpecialInt - | SplitStrategy; + | SplitStrategy + | WithDotTemplateStrategy + | ArrayToAdbDateStrategy; type SourceElement = { path: string; - expectedSchema?: JsonSchema; + expectedSchema?: JSONSchema7; }; export type DeclarativeSimpleMapping = { @@ -672,7 +968,7 @@ export type DeclarativeSimpleMapping = { export type FlatSourceElement = { columns: string[] | number[]; - expectedSchema?: JsonSchema; + expectedSchema?: JSONSchema7; }; export type DeclarativeFlatMapping = { @@ -710,4 +1006,6 @@ export const strategyFunctionMap: { [strategyId: string]: StrategyFunction } = { constant: constantStrategy, split: splitStrategy, dateArrayToSpecialInt, + withDotTemplate, + arrayToAdbDate, }; diff --git a/apps/exhibition-live/components/utils/mapping/mapMatchBasedByConfig.ts b/packages/data-mapping/src/matchBased2DeclarativeFlatMapping.ts similarity index 53% rename from apps/exhibition-live/components/utils/mapping/mapMatchBasedByConfig.ts rename to packages/data-mapping/src/matchBased2DeclarativeFlatMapping.ts index a62e8148..642b4e1c 100644 --- a/apps/exhibition-live/components/utils/mapping/mapMatchBasedByConfig.ts +++ b/packages/data-mapping/src/matchBased2DeclarativeFlatMapping.ts @@ -1,24 +1,28 @@ -import { OwnColumnDesc } from "../../google/types"; -import { AnyFlatStrategy, DeclarativeFlatMapping } from "./mappingStrategies"; +import { + AnyFlatStrategy, + DeclarativeFlatMapping, + DeclarativeFlatMappings, +} from "./mappingStrategies"; import flatten from "lodash/flatten"; import uniq from "lodash/uniq"; -import { JsonSchema } from "@jsonforms/core"; import dot from "dot"; +import { JSONSchema7 } from "json-schema"; +import { filterUndefOrNull } from "@slub/edb-core-utils"; -export const indexFromLetter = ( - letter: string, - fields: OwnColumnDesc[], -): number => { +type OwnColumnDesc = { + index: number; + value: string | number | null | boolean | any; + letter: string; +}; + +const indexFromLetter = (letter: string, fields: OwnColumnDesc[]): number => { const index = fields.findIndex((m) => m.letter === letter); if (index === -1) { throw new Error(`No index for letter ${letter}`); } return index; }; -export const indexFromTitle = ( - title: string, - fields: OwnColumnDesc[], -): number => { +const indexFromTitle = (title: string, fields: OwnColumnDesc[]): number => { const index = fields.findIndex((m) => m.value === title); if (index === -1) { throw new Error(`No index for title ${title}`); @@ -27,6 +31,7 @@ export const indexFromTitle = ( }; type MatchByTitle = { title: string[]; + includeRightNeighbours?: number; }; type MatchNColumnsByTitlePattern = { titlePattern: string; @@ -36,7 +41,7 @@ type MatchNColumnsByTitlePattern = { export type FlexibleColumnMatchingDefinition = | MatchByTitle | MatchNColumnsByTitlePattern; -export const isTitlePattern = ( +const isTitlePattern = ( definition: FlexibleColumnMatchingDefinition, ): definition is MatchNColumnsByTitlePattern => { return (definition as MatchNColumnsByTitlePattern).titlePattern !== undefined; @@ -46,6 +51,20 @@ const resolveTitlePattern = (pattern: string, data: any): string => { return template(data); }; +const includeRightNeighbours = ( + firstIndex: number, + count?: number, +): number[] => { + if (typeof count === "number") { + if (count <= 0) { + throw new Error("includeRightNeighbours must be greater than 0"); + } + return [...Array(count + 1)].map((_, i) => firstIndex + i); + } else { + return [firstIndex]; + } +}; + const columnMatcherImplementation = ( fields: OwnColumnDesc[], definition: FlexibleColumnMatchingDefinition, @@ -57,21 +76,18 @@ const columnMatcherImplementation = ( const title = resolveTitlePattern(definition.titlePattern, { i }); return indexFromTitle(title, fields); }) - .map((firstIndex) => { - if (typeof definition.includeRightNeighbours === "number") { - if (definition.includeRightNeighbours <= 0) { - throw new Error("includeRightNeighbours must be greater than 0"); - } - return [...Array(definition.includeRightNeighbours + 1)].map( - (_, i) => firstIndex + i, - ); - } else { - return [firstIndex]; - } - }), + .map((firstIndex) => + includeRightNeighbours(firstIndex, definition.includeRightNeighbours), + ), ); } else { - return definition.title.map((title) => indexFromTitle(title, fields)); + return flatten( + definition.title + .map((title) => indexFromTitle(title, fields)) + .map((firstIndex) => + includeRightNeighbours(firstIndex, definition.includeRightNeighbours), + ), + ); } }; /** @@ -87,7 +103,7 @@ const columnMatcher = ( export type FlatSourceMatchBased = { columns: FlexibleColumnMatchingDefinition; - expectedSchema?: JsonSchema; + expectedSchema?: JSONSchema7; }; export type DeclarativeMatchBasedFlatMapping = { id: string; @@ -101,6 +117,19 @@ export type DeclarativeMatchBasedFlatMapping = { }; export type DeclarativeMatchBasedFlatMappings = DeclarativeMatchBasedFlatMapping[]; + +/** + * Converts a match based flat mapping to a declarative flat mapping + * + * the match based flat mapping is a more flexible way to define mappings upon tables that + * can change over time, where a column index is not a stable identifier + * + * in order to use the flat mapping, column indices need to resolved based on the given + * titles or title patterns within the table header, this is done by the {@link columnMatcher} + * + * @param fields + * @param mapping + */ export const matchBased2DeclarativeFlatMapping = ( fields: OwnColumnDesc[], mapping: DeclarativeMatchBasedFlatMapping, @@ -113,3 +142,23 @@ export const matchBased2DeclarativeFlatMapping = ( }, }; }; +export const matchBased2DeclarativeFlatMappings: ( + fields: OwnColumnDesc[], + matchBasedFlatMappings: DeclarativeMatchBasedFlatMappings, + options?: { + throwOnMappingError?: boolean; + }, +) => DeclarativeFlatMappings = (fields, matchBasedFlatMappings, options) => + filterUndefOrNull( + matchBasedFlatMappings.map((mapping) => { + let res = null; + try { + res = matchBased2DeclarativeFlatMapping(fields, mapping); + } catch (e) { + if (options?.throwOnMappingError) { + throw e; + } + } + return res; + }), + ); diff --git a/apps/exhibition-live/components/utils/mapping/simpleFieldExtractor.ts b/packages/data-mapping/src/simpleFieldExtractor.ts similarity index 95% rename from apps/exhibition-live/components/utils/mapping/simpleFieldExtractor.ts rename to packages/data-mapping/src/simpleFieldExtractor.ts index a6895084..5dfa8e61 100644 --- a/apps/exhibition-live/components/utils/mapping/simpleFieldExtractor.ts +++ b/packages/data-mapping/src/simpleFieldExtractor.ts @@ -1,9 +1,9 @@ +import get from "lodash-es/get"; import { FieldExtractDeclaration, PrimaryFieldExtract, PrimaryFieldResults, -} from "../types"; -import get from "lodash/get"; +} from "@slub/edb-core-types"; export const extractFieldAny = ( entry: any | null, diff --git a/packages/data-mapping/src/types.ts b/packages/data-mapping/src/types.ts new file mode 100644 index 00000000..38a8eab6 --- /dev/null +++ b/packages/data-mapping/src/types.ts @@ -0,0 +1,12 @@ +export type MappingOptions = { + throwOnAttributeError?: boolean; +}; + +export type ProcessFlatResourceFn = ( + headerCallback: (header: string[]) => Promise, + recordCallback: (record: string[], index: number) => Promise, + amount?: number, + offset?: number, +) => Promise; + +export type DeclarativeMappingTypeMap = Record; diff --git a/packages/data-mapping/tsconfig.json b/packages/data-mapping/tsconfig.json new file mode 100644 index 00000000..85d375a5 --- /dev/null +++ b/packages/data-mapping/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "@slub/edb-tsconfig/base.json", + "include": ["."], + "exclude": ["dist", "build", "node_modules"], + "compilerOptions": { + "lib": ["es2022", "dom"], + "strictNullChecks": false, + "resolveJsonModule": true, + "esModuleInterop": true + } +} + diff --git a/packages/data-mapping/tsup.config.js b/packages/data-mapping/tsup.config.js new file mode 100644 index 00000000..85b8dcc3 --- /dev/null +++ b/packages/data-mapping/tsup.config.js @@ -0,0 +1,5 @@ +import { makeConfigWithExternals } from "@slub/edb-tsup-config/tsup.config.js"; +import pkg from "./package.json"; + +const config = makeConfigWithExternals(pkg); +export default config; diff --git a/packages/debug-utils/package.json b/packages/debug-utils/package.json new file mode 100644 index 00000000..462bdd62 --- /dev/null +++ b/packages/debug-utils/package.json @@ -0,0 +1,44 @@ +{ + "name": "@slub/edb-debug-utils", + "description": "Frontend Debug utilities for the EDB framework", + "version": "1.0.0", + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.js", + "require": "./dist/index.cjs", + "default": "./dist/index.js", + "types": "./dist/index.d.ts" + } + }, + "scripts": { + "build": "tsup src/index.tsx --format esm,cjs --dts --external react", + "dev": "tsup src/index.tsx --format esm,cjs --watch --dts --external react", + "lint": "eslint \"**/*.ts*\"", + "lint-fix": "eslint --fix \"**/*.ts*\"", + "test": "jest", + "test:watch": "jest --watch --color", + "test:coverage": "jest --coverage", + "doc": "typedoc" + }, + "devDependencies": { + "@slub/edb-tsconfig": "workspace:*", + "@slub/edb-tsup-config": "workspace:*", + "@types/jest": "^29.5.12", + "@types/react": "^18.3.1" + }, + "peerDependencies": { + "next": ">14", + "react": "^16.9.0 || ^17.0.0 || ^18", + "@mui/material": "^5", + "@mui/lab": "^5" + }, + "dependencies": { + "@slub/edb-state-hooks": "workspace:*", + "@slub/edb-core-types": "workspace:*", + "@triply/yasgui": "^4.2.28" + } +} diff --git a/apps/exhibition-live/components/form/FormDebuggingTools.tsx b/packages/debug-utils/src/FormDebuggingTools.tsx similarity index 74% rename from apps/exhibition-live/components/form/FormDebuggingTools.tsx rename to packages/debug-utils/src/FormDebuggingTools.tsx index ed4670ad..612d7aa1 100644 --- a/apps/exhibition-live/components/form/FormDebuggingTools.tsx +++ b/packages/debug-utils/src/FormDebuggingTools.tsx @@ -1,9 +1,9 @@ import { JsonView } from "react-json-view-lite"; import { Divider, Grid, Typography } from "@mui/material"; import React from "react"; -import { useSettings } from "../state/useLocalSettings"; -import SPARQLLocalOxigraphToolkit from "../utils/dev/SPARQLLocalOxigraphToolkit"; -import { useGlobalCRUDOptions } from "../state/useGlobalCRUDOptions"; +import { useSettings } from "@slub/edb-state-hooks"; +import { useGlobalCRUDOptions } from "@slub/edb-state-hooks"; +import { SPARQLLocalOxigraphToolkit } from "./SPARQLLocalOxigraphToolkit"; type FormDebuggingToolsProps = { jsonData?: Record; @@ -19,7 +19,7 @@ export const FormDebuggingTools = ({ jsonData }: FormDebuggingToolsProps) => { return ( {key} - lvl < 5} /> + lvl < 5} /> ); diff --git a/apps/exhibition-live/components/utils/dev/SPARQLLocalOxigraphToolkit.tsx b/packages/debug-utils/src/SPARQLLocalOxigraphToolkit.tsx similarity index 84% rename from apps/exhibition-live/components/utils/dev/SPARQLLocalOxigraphToolkit.tsx rename to packages/debug-utils/src/SPARQLLocalOxigraphToolkit.tsx index 22f165d9..34695440 100644 --- a/apps/exhibition-live/components/utils/dev/SPARQLLocalOxigraphToolkit.tsx +++ b/packages/debug-utils/src/SPARQLLocalOxigraphToolkit.tsx @@ -1,7 +1,6 @@ import Yasgui from "@triply/yasgui"; import React, { FunctionComponent, useCallback, useState } from "react"; - -import SPARQLToolkit from "./SPARQLToolkit"; +import { SPARQLToolkit } from "./SPARQLToolkit"; interface OwnProps { sparqlQuery?: (query: string) => Promise; @@ -9,7 +8,7 @@ interface OwnProps { type Props = OwnProps; -const SPARQLLocalOxigraphToolkit: FunctionComponent = ({ +export const SPARQLLocalOxigraphToolkit: FunctionComponent = ({ sparqlQuery, }) => { const [yasgui, setYasgui] = useState(null); @@ -33,5 +32,3 @@ const SPARQLLocalOxigraphToolkit: FunctionComponent = ({ /> ); }; - -export default SPARQLLocalOxigraphToolkit; diff --git a/apps/exhibition-live/components/utils/dev/SPARQLToolkit.tsx b/packages/debug-utils/src/SPARQLToolkit.tsx similarity index 64% rename from apps/exhibition-live/components/utils/dev/SPARQLToolkit.tsx rename to packages/debug-utils/src/SPARQLToolkit.tsx index 1331e35f..8f51ca7f 100644 --- a/apps/exhibition-live/components/utils/dev/SPARQLToolkit.tsx +++ b/packages/debug-utils/src/SPARQLToolkit.tsx @@ -2,9 +2,10 @@ import { ToggleButton } from "@mui/lab"; import { Button } from "@mui/material"; import React, { FunctionComponent, useState } from "react"; -import YasguiSPARQLEditorNoSSR, { - YasguiSPARQLEditorProps, -} from "./YasguiSPARQLEditorNoSSR"; +import { YasguiSPARQLEditorNoSSR } from "./YasguiSPARQLEditorNoSSR"; +import { useAdbContext } from "@slub/edb-state-hooks"; + +import { YasguiSPARQLEditorProps } from "./YasguiSPARQLEditorProps"; interface OwnProps { onSendClicked?: () => void; @@ -12,16 +13,19 @@ interface OwnProps { type Props = OwnProps & YasguiSPARQLEditorProps; -const SPARQLToolkit: FunctionComponent = ({ +export const SPARQLToolkit: FunctionComponent = ({ onSendClicked, ...props }) => { const [editorEnabled, setEditorEnabled] = useState(false); + const { + queryBuildOptions: { prefixes }, + } = useAdbContext(); return ( <> {editorEnabled ? ( <> - + @@ -36,5 +40,3 @@ const SPARQLToolkit: FunctionComponent = ({ ); }; - -export default SPARQLToolkit; diff --git a/packages/debug-utils/src/YasguiSPARQLEditor.tsx b/packages/debug-utils/src/YasguiSPARQLEditor.tsx new file mode 100644 index 00000000..96e35c39 --- /dev/null +++ b/packages/debug-utils/src/YasguiSPARQLEditor.tsx @@ -0,0 +1,46 @@ +import type Yasgui from "@triply/yasgui"; +import React, { FunctionComponent, useEffect, useState } from "react"; + +import { Prefixes } from "@slub/edb-core-types"; +import { YasguiSPARQLEditorProps } from "./YasguiSPARQLEditorProps"; + +const withPrefixes = (yg: Yasgui, prefixes?: Prefixes) => { + const yasqe = yg.getTab(yg.persistentConfig.currentId())?.getYasqe(); + const yasqr = yg.getTab(yg.persistentConfig.currentId())?.getYasr(); + prefixes && yasqe?.addPrefixes(prefixes); + //yasqr?.set + return yg; +}; + +const YasguiSPARQLEditor: FunctionComponent = ({ + onInit, + prefixes, +}) => { + const [yasgui, setYasgui] = useState(null); + + useEffect(() => { + import("@triply/yasgui").then(({ default: YasguiCls }) => { + setYasgui((yg) => { + const el = document.getElementById("yasgui"); + return !el || yg + ? yg + : withPrefixes( + new YasguiCls(el, { + yasqe: { + queryingDisabled: undefined, + showQueryButton: true, + }, + }), + prefixes, + ); + }); + }); + }, [setYasgui]); + useEffect(() => { + if (yasgui && onInit) onInit(yasgui); + }, [onInit, yasgui]); + + return
; +}; + +export default YasguiSPARQLEditor; diff --git a/apps/exhibition-live/components/utils/dev/YasguiSPARQLEditorNoSSR.tsx b/packages/debug-utils/src/YasguiSPARQLEditorNoSSR.tsx similarity index 50% rename from apps/exhibition-live/components/utils/dev/YasguiSPARQLEditorNoSSR.tsx rename to packages/debug-utils/src/YasguiSPARQLEditorNoSSR.tsx index aab72f9c..26a8d4de 100644 --- a/apps/exhibition-live/components/utils/dev/YasguiSPARQLEditorNoSSR.tsx +++ b/packages/debug-utils/src/YasguiSPARQLEditorNoSSR.tsx @@ -1,9 +1,6 @@ -import type Yasgui from "@triply/yasgui"; import dynamic from "next/dynamic"; +import { YasguiSPARQLEditorProps } from "./YasguiSPARQLEditorProps"; -export interface YasguiSPARQLEditorProps { - onInit?: (yasgu: Yasgui) => void; -} const DynamicComponentWithNoSSR = dynamic( () => import("./YasguiSPARQLEditor"), { @@ -11,7 +8,6 @@ const DynamicComponentWithNoSSR = dynamic( }, ); -// @ts-ignore -export default (props: YasguiSPARQLEditorProps) => ( +export const YasguiSPARQLEditorNoSSR = (props: YasguiSPARQLEditorProps) => ( ); diff --git a/packages/debug-utils/src/YasguiSPARQLEditorProps.ts b/packages/debug-utils/src/YasguiSPARQLEditorProps.ts new file mode 100644 index 00000000..0b2ee184 --- /dev/null +++ b/packages/debug-utils/src/YasguiSPARQLEditorProps.ts @@ -0,0 +1,7 @@ +import type Yasgui from "@triply/yasgui"; +import { Prefixes } from "@slub/edb-core-types"; + +export type YasguiSPARQLEditorProps = { + onInit?: (yasgu: Yasgui) => void; + prefixes?: Prefixes; +}; diff --git a/packages/debug-utils/src/index.tsx b/packages/debug-utils/src/index.tsx new file mode 100644 index 00000000..6703a06a --- /dev/null +++ b/packages/debug-utils/src/index.tsx @@ -0,0 +1 @@ +export * from "./FormDebuggingTools"; diff --git a/packages/debug-utils/tsconfig.json b/packages/debug-utils/tsconfig.json new file mode 100644 index 00000000..6c393f43 --- /dev/null +++ b/packages/debug-utils/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "@slub/edb-tsconfig/react-library.json", + "include": ["."], + "exclude": ["dist", "build", "node_modules"], + "compilerOptions": { + "strict": false, + "resolveJsonModule": true + } +} diff --git a/packages/debug-utils/tsup.config.js b/packages/debug-utils/tsup.config.js new file mode 100644 index 00000000..85b8dcc3 --- /dev/null +++ b/packages/debug-utils/tsup.config.js @@ -0,0 +1,5 @@ +import { makeConfigWithExternals } from "@slub/edb-tsup-config/tsup.config.js"; +import pkg from "./package.json"; + +const config = makeConfigWithExternals(pkg); +export default config; diff --git a/packages/edb-cli-creator/package.json b/packages/edb-cli-creator/package.json new file mode 100644 index 00000000..d32bfec9 --- /dev/null +++ b/packages/edb-cli-creator/package.json @@ -0,0 +1,42 @@ +{ + "name": "@slub/edb-cli-creator", + "version": "1.1.0", + "description": "CLI creator from the EDB framework", + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.js", + "require": "./dist/index.cjs", + "default": "./dist/index.js", + "types": "./dist/index.d.ts" + } + }, + "scripts": { + "build": "tsup", + "dev": "tsup --watch", + "lint": "eslint \"**/*.ts*\"", + "lint-fix": "eslint --fix \"**/*.ts*\"", + "test": "NODE_OPTIONS=--experimental-vm-modules jest --passWithNoTests --color", + "test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch --color", + "test:coverage": "NODE_OPTIONS=--experimental-vm-modules jest --coverage", + "doc": "typedoc" + }, + "devDependencies": { + "@slub/edb-build-helper": "workspace:*", + "@slub/edb-core-types": "workspace:*", + "@slub/edb-tsconfig": "workspace:*", + "@slub/edb-tsup-config": "workspace:*", + "@slub/edb-data-mapping": "workspace:*", + "@types/jest": "^29.5.12", + "@types/json-schema": "^7.0.14", + "eslint-config-edb": "workspace:*", + "typescript": "^5.3.3" + }, + "dependencies": { + "@slub/edb-core-utils": "workspace:*", + "cmd-ts": "^0.13.0" + } +} diff --git a/packages/edb-cli-creator/src/index.ts b/packages/edb-cli-creator/src/index.ts new file mode 100644 index 00000000..80f05c5d --- /dev/null +++ b/packages/edb-cli-creator/src/index.ts @@ -0,0 +1 @@ +export * from "./makeEdbCli"; diff --git a/packages/edb-cli-creator/src/makeEdbCli.ts b/packages/edb-cli-creator/src/makeEdbCli.ts new file mode 100644 index 00000000..53bf6461 --- /dev/null +++ b/packages/edb-cli-creator/src/makeEdbCli.ts @@ -0,0 +1,384 @@ +import { + AbstractDatastore, + AvailableFlatMappings, +} from "@slub/edb-global-types"; +import { formatJSONResult } from "@slub/edb-core-utils"; +import { + boolean, + command, + flag, + number, + oneOf, + option, + optional, + positional, + string, +} from "cmd-ts"; +import { JSONSchema7 } from "json-schema"; +import { defs } from "@slub/json-schema-utils"; +import { File } from "cmd-ts/batteries/fs"; +import { AuthorityConfiguration } from "@slub/edb-data-mapping"; + +export type FlatImportHandler = (option: { + file: string; + mimeType: string | undefined; + mappingDeclaration: string; + amount: number | undefined; + offset: number | undefined; + dryRun: boolean; + debug: boolean; +}) => Promise; + +export type SemanticSeedHandler = (option: { + file: string; + schema: JSONSchema7; + onDocument: ( + entityIRI: string, + typeIRI: string, + document: any, + ) => Promise; +}) => Promise; +export type MapFromAuthorityHandlerOptions = { + enableLogging?: string; +}; +export type MapFromAuthorityHandler = ( + id: string | undefined, + classIRI: string, + entryData: any, + authorityIRI: string, + limit: number, + options?: MapFromAuthorityHandlerOptions, +) => Promise; + +export const makeEdbCli = ( + schema: JSONSchema7, + dataStore: AbstractDatastore, + importStores: Record, + flatMappings?: AvailableFlatMappings, + flatImportHandler?: FlatImportHandler, + semanticImportHandler?: SemanticSeedHandler, + mapFromAuthority?: MapFromAuthorityHandler, + authorityConfigurations?: Record, +) => { + const types = Object.keys(defs(schema)); + const get = command({ + name: "edb-cli get", + args: { + entityIRI: positional({ + type: string, + displayName: "entityIRI", + description: "the IRI of the entity to fetch", + }), + type: option({ + type: optional(string), + description: "The Type of the document", + long: "type", + short: "t", + }), + pretty: flag({ + type: boolean, + description: "Pretty print the output", + long: "pretty", + short: "p", + }), + noJsonld: flag({ + type: boolean, + description: "Filter JSON-LD properties", + long: "no-jsonld", + }), + }, + handler: async ({ entityIRI, type, pretty, noJsonld }) => { + if (!type) { + throw new Error( + "Loading an entity without type currently not supported", + ); + } + const item = await dataStore.loadDocument(type, entityIRI); + console.log(formatJSONResult(item, pretty, noJsonld)); + }, + }); + + const list = command({ + name: "edb-cli list", + args: { + type: positional({ + type: oneOf(types), + displayName: "type", + description: "The Type of the documents to be listed", + }), + amount: option({ + type: optional(number), + description: "The amount of documents to fetch", + long: "amount", + short: "n", + }), + search: option({ + type: optional(string), + description: "The search string", + long: "search", + short: "s", + }), + pretty: flag({ + type: boolean, + description: "Pretty print the output", + long: "pretty", + short: "p", + }), + noJsonld: flag({ + type: boolean, + description: "Filter JSON-LD properties", + long: "no-jsonld", + }), + }, + handler: async ({ type, amount = 1, search, pretty, noJsonld }) => { + await dataStore.findDocuments(type, { search }, amount, (item) => { + console.log(formatJSONResult(item, pretty, noJsonld)); + return Promise.resolve(); + }); + process.exit(0); + }, + }); + + const flatImport = + flatMappings && + flatImportHandler && + command({ + name: "edb-cli flat-import", + description: "Import of flat table structured documents", + args: { + file: positional({ + type: File, + displayName: "File Path", + description: "The path to the file to import", + }), + mappingDeclaration: option({ + type: oneOf(Object.keys(flatMappings)), + description: `The flat mapping to use for the import (can available: ${Object.keys( + flatMappings, + ) + .map((k) => `"${k}"`) + .join(",")} )`, + long: "mapping", + short: "m", + }), + mimeType: option({ + type: optional(oneOf(["application/csv", "application/json"])), + description: "The MIME type of the document to import", + defaultValue: () => "application/csv", + defaultValueIsSerializable: true, + long: "mime-type", + short: "mime", + }), + amount: option({ + type: optional(number), + description: "The amount of rows to import", + long: "amount", + short: "n", + }), + offset: option({ + type: optional(number), + description: "The offset to start importing from", + long: "offset", + short: "o", + }), + dryRun: flag({ + type: boolean, + description: "Do not import the data, just show the mapped data", + long: "dry-run", + short: "d", + }), + debug: flag({ + type: boolean, + description: "Enable debug logging", + long: "debug", + }), + }, + handler: flatImportHandler, + }); + + const importFromAuthority = + authorityConfigurations && + mapFromAuthority && + command({ + name: "import-from-authority", + description: "Import data from an authority source", + args: { + id: positional({ + type: string, + description: "The ID of the entity in the authority source", + }), + type: option({ + type: string, + description: "The Type of the document, that should be imported", + long: "type", + short: "t", + }), + authorityIRI: option({ + type: string, + description: "The IRI of the authority source", + long: "authority-iri", + short: "au", + }), + limit: option({ + type: optional(number), + description: "The maximum number of results to return", + long: "limit", + defaultValue: () => 1, + }), + pretty: flag({ + type: boolean, + description: "Pretty print the output", + long: "pretty", + short: "p", + }), + noJsonld: flag({ + type: boolean, + description: "Filter JSON-LD properties", + long: "no-jsonld", + }), + debug: flag({ + type: boolean, + description: "Enable debug logging", + long: "debug", + }), + }, + handler: async ({ + id, + type, + authorityIRI, + limit, + pretty, + noJsonld, + debug, + }) => { + try { + const authConfig = authorityConfigurations[authorityIRI]; + if (!authConfig) + throw new Error( + `no authority configuration found for ${authorityIRI}`, + ); + const entryData = await authConfig.getEntityByIRI(id); + if (!entryData) throw new Error(`no entry data found for ${id}`); + const result = await mapFromAuthority( + id, + dataStore.typeNameToTypeIRI(type), + { + allProps: entryData, + }, + authorityIRI, + limit || 1, + debug ? { enableLogging: "debug" } : undefined, + ); + console.log(formatJSONResult(result, pretty, noJsonld)); + } catch (error) { + console.error("Error importing from authority:", error); + process.exit(1); + } + process.exit(0); + }, + }); + + const importCommand = command({ + name: "import", + description: "Recursively import data from another data store", + args: { + typeName: positional({ + type: oneOf(types), + displayName: "type", + description: "The Type of the document", + }), + importStoreName: option({ + type: oneOf(Object.keys(importStores)), + long: "importFrom", + short: "i", + description: `the store where data should be imported (${Object.keys(importStores).join(" , ")})`, + }), + entityIRI: option({ + type: optional(string), + long: "entityIRI", + short: "e", + description: "only import a single entity identified by the entityIRI", + }), + limit: option({ + type: optional(number), + description: "The number of documents to import", + defaultValue: () => 10000, + long: "limit", + short: "l", + }), + }, + handler: async ({ entityIRI, typeName, importStoreName, limit }) => { + const importStore = importStores[importStoreName]; + if (!importStore) { + throw new Error(`import store ${importStoreName} not found in config`); + process.exit(1); + } + if (entityIRI) { + await dataStore.importDocument(typeName, entityIRI, importStore); + } else { + await dataStore.importDocuments(typeName, importStore, limit || 10); + } + process.exit(0); + }, + }); + + const seed = command({ + name: "seed", + description: "Seed the database with data from a file", + args: { + file: positional({ + type: File, + displayName: "File Path", + description: + "The path to the file to import (Turtle, N-Triples, JSON-LD)", + }), + dryRun: flag({ + type: optional(boolean), + description: "Do not import the data, just show the mapped data", + long: "dry-run", + short: "d", + }), + pretty: flag({ + type: boolean, + description: "Pretty print the output", + long: "pretty", + short: "p", + }), + noJsonld: flag({ + type: boolean, + description: "Filter JSON-LD properties", + long: "no-jsonld", + }), + }, + + handler: async ({ file, dryRun, pretty, noJsonld }) => { + if (!semanticImportHandler) { + throw new Error("Semantic import not supported"); + } + await semanticImportHandler({ + file, + schema, + onDocument: async (entityIRI, typeIRI, document) => { + const result = !dryRun + ? await dataStore.upsertDocument( + dataStore.typeIRItoTypeName(typeIRI), + entityIRI, + document, + ) + : document; + console.log(formatJSONResult(result, pretty, noJsonld)); + }, + }); + process.exit(0); + }, + }); + + return { + list, + get, + flatImport, + import: importCommand, + importFromAuthority, + seed, + }; +}; diff --git a/packages/edb-cli-creator/tsconfig.json b/packages/edb-cli-creator/tsconfig.json new file mode 100644 index 00000000..3e9b3cb6 --- /dev/null +++ b/packages/edb-cli-creator/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "@slub/edb-tsconfig/base.json", + "include": ["src"], + "exclude": ["dist", "build", "node_modules"], + "compilerOptions": { + "resolveJsonModule": true, + "strict": true, + "lib": ["esnext"] + } +} diff --git a/packages/edb-cli-creator/tsup.config.js b/packages/edb-cli-creator/tsup.config.js new file mode 100644 index 00000000..85b8dcc3 --- /dev/null +++ b/packages/edb-cli-creator/tsup.config.js @@ -0,0 +1,5 @@ +import { makeConfigWithExternals } from "@slub/edb-tsup-config/tsup.config.js"; +import pkg from "./package.json"; + +const config = makeConfigWithExternals(pkg); +export default config; diff --git a/packages/edb-default-theme/package.json b/packages/edb-default-theme/package.json new file mode 100644 index 00000000..f665b6c0 --- /dev/null +++ b/packages/edb-default-theme/package.json @@ -0,0 +1,24 @@ +{ + "name": "@slub/edb-default-theme", + "version": "1.0.0", + "private": true, + "main": "src/index.tsx", + "types": "src/index.tsx", + "sideEffects": false, + "scripts": { + "typecheck": "tsc -b", + "lint": "eslint \"**/*.ts*\"", + "lint-fix": "eslint --fix \"**/*.ts*\"" + }, + "peerDependencies": { + "@mui/material": "^5", + "@mui/icons-material": "^5", + "react": "^18" + }, + "dependencies": { + }, + "devDependencies": { + "@slub/edb-build-helper": "workspace:*" + } +} + diff --git a/apps/exhibition-live/components/theme/ThemeComponent.tsx b/packages/edb-default-theme/src/ThemeComponent.tsx similarity index 69% rename from apps/exhibition-live/components/theme/ThemeComponent.tsx rename to packages/edb-default-theme/src/ThemeComponent.tsx index d076811f..9636382f 100644 --- a/apps/exhibition-live/components/theme/ThemeComponent.tsx +++ b/packages/edb-default-theme/src/ThemeComponent.tsx @@ -5,7 +5,6 @@ import { ReactNode, useMemo } from "react"; // ** Type Imports // ** Theme Config -import { useThemeSettings } from "../state"; import theme from "./berry-theme"; // ** Global Styles import GlobalStyling from "./globalStyles"; @@ -16,13 +15,20 @@ interface Props { children: ReactNode; } -const ThemeComponent = (props: Props) => { - const themeSettings = useThemeSettings(); +const themeSettings = { + isOpen: [], // for active default menu + defaultId: "default", + fontFamily: "sans-serif", + borderRadius: 12, + opened: true, + navType: "light", +} as const; + +const themeFinal = theme(themeSettings); +export const ThemeComponent = (props: Props) => { // ** Props const { children } = props; - const themeFinal = useMemo(() => theme(themeSettings), [themeSettings]); - return ( @@ -31,5 +37,3 @@ const ThemeComponent = (props: Props) => { ); }; - -export default ThemeComponent; diff --git a/apps/exhibition-live/components/theme/berry-theme/compStyleOverride.ts b/packages/edb-default-theme/src/berry-theme/compStyleOverride.ts similarity index 88% rename from apps/exhibition-live/components/theme/berry-theme/compStyleOverride.ts rename to packages/edb-default-theme/src/berry-theme/compStyleOverride.ts index e0832f90..eda767f4 100644 --- a/apps/exhibition-live/components/theme/berry-theme/compStyleOverride.ts +++ b/packages/edb-default-theme/src/berry-theme/compStyleOverride.ts @@ -1,8 +1,32 @@ +import { Padding } from "@mui/icons-material"; import { ThemeExtended } from "./themeType"; export default function componentStyleOverrides(theme: ThemeExtended) { const bgColor = theme.colors?.grey50; + const variant = theme.variant || "outlined"; return { + MuiTextField: { + defaultProps: { + variant, + }, + }, + MuiSelect: { + defaultProps: { + variant, + }, + }, + // avoid jammed look of input fields when variant is not 'standard' + ...(variant !== "standard" + ? { + MuiFormControl: { + styleOverrides: { + root: { + marginTop: "8px", + }, + }, + }, + } + : {}), MuiAppBar: { styleOverrides: { root: { @@ -43,21 +67,28 @@ export default function componentStyleOverrides(theme: ThemeExtended) { }, }, }, + MuiAutocomplete: { + styleOverrides: { + root: { + paddingTop: "8px", + }, + }, + }, MuiCardHeader: { styleOverrides: { root: { color: theme.colors?.textDark, - padding: "24px", + padding: "0", }, title: { - fontSize: "1.125rem", + fontSize: "1.5rem", }, }, }, MuiCardContent: { styleOverrides: { root: { - padding: "24px", + padding: "0", }, }, }, diff --git a/apps/exhibition-live/components/theme/berry-theme/index.ts b/packages/edb-default-theme/src/berry-theme/index.ts similarity index 86% rename from apps/exhibition-live/components/theme/berry-theme/index.ts rename to packages/edb-default-theme/src/berry-theme/index.ts index 7e50b3de..ad5a6c30 100644 --- a/apps/exhibition-live/components/theme/berry-theme/index.ts +++ b/packages/edb-default-theme/src/berry-theme/index.ts @@ -1,14 +1,16 @@ -import { ThemeOptions } from "@mui/material"; +import { TextFieldProps, ThemeOptions } from "@mui/material"; import { createTheme, Theme } from "@mui/material/styles"; // assets -import colors from "../../../styles/_themes-vars.module.scss"; +// @ts-ignore +import colors from "./themes-vars.module.scss"; // project imports import componentStyleOverrides from "./compStyleOverride"; import themePalette from "./palette"; import { ThemeExtended } from "./themeType"; import themeTypography from "./typography"; +let variant: "outlined" | "standard" | "filled" = "outlined"; export const theme = (customization: ThemeExtended["customization"]) => { const color = colors; @@ -24,6 +26,7 @@ export const theme = (customization: ThemeExtended["customization"]) => { menuSelected: color.secondaryDark, menuSelectedBack: color.secondaryLight, divider: color.grey200, + variant, customization, }; diff --git a/apps/exhibition-live/components/theme/berry-theme/palette.ts b/packages/edb-default-theme/src/berry-theme/palette.ts similarity index 100% rename from apps/exhibition-live/components/theme/berry-theme/palette.ts rename to packages/edb-default-theme/src/berry-theme/palette.ts diff --git a/apps/exhibition-live/components/theme/berry-theme/themeType.ts b/packages/edb-default-theme/src/berry-theme/themeType.ts similarity index 96% rename from apps/exhibition-live/components/theme/berry-theme/themeType.ts rename to packages/edb-default-theme/src/berry-theme/themeType.ts index dafb8777..8d866434 100644 --- a/apps/exhibition-live/components/theme/berry-theme/themeType.ts +++ b/packages/edb-default-theme/src/berry-theme/themeType.ts @@ -46,6 +46,7 @@ export interface ThemeExtended { heading: string; backgroundDefault: string; background: string; + variant?: "outlined" | "standard" | "filled"; customization?: { fontFamily: string; borderRadius: number; diff --git a/apps/exhibition-live/styles/_themes-vars.module.scss b/packages/edb-default-theme/src/berry-theme/themes-vars.module.scss similarity index 100% rename from apps/exhibition-live/styles/_themes-vars.module.scss rename to packages/edb-default-theme/src/berry-theme/themes-vars.module.scss diff --git a/apps/exhibition-live/components/theme/berry-theme/typography.ts b/packages/edb-default-theme/src/berry-theme/typography.ts similarity index 100% rename from apps/exhibition-live/components/theme/berry-theme/typography.ts rename to packages/edb-default-theme/src/berry-theme/typography.ts diff --git a/apps/exhibition-live/components/theme/globalStyles.ts b/packages/edb-default-theme/src/globalStyles.ts similarity index 100% rename from apps/exhibition-live/components/theme/globalStyles.ts rename to packages/edb-default-theme/src/globalStyles.ts diff --git a/packages/edb-default-theme/src/index.tsx b/packages/edb-default-theme/src/index.tsx new file mode 100644 index 00000000..856c7cec --- /dev/null +++ b/packages/edb-default-theme/src/index.tsx @@ -0,0 +1 @@ +export * from "./ThemeComponent"; diff --git a/packages/edb-default-theme/tsconfig.json b/packages/edb-default-theme/tsconfig.json new file mode 100644 index 00000000..9db70c96 --- /dev/null +++ b/packages/edb-default-theme/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "@slub/edb-tsconfig/react-library.json", + "include": ["src"], + "exclude": ["dist", "build", "node_modules"], + "compilerOptions": { + "strict": false, + "resolveJsonModule": true + } +} diff --git a/packages/edb-sparnatural/install-jsonschema2shacl.sh b/packages/edb-sparnatural/install-jsonschema2shacl.sh new file mode 100755 index 00000000..00f8c4c0 --- /dev/null +++ b/packages/edb-sparnatural/install-jsonschema2shacl.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +if [ ! -f "jsonschema2shacl/requirements.txt" ]; then + while true; do + read -p "Submodules not initialized. Initialize now? (Y/N): " yn + case $yn in + [Yy]* ) git submodule update --init --recursive; break;; + [Nn]* ) echo "Exiting without initializing submodules."; exit 1;; + * ) echo "Please answer Yes or No.";; + esac + done +fi + +python3 -m venv .venv || true +.venv/bin/pip install -r jsonschema2shacl/requirements.txt diff --git a/packages/edb-sparnatural/jsonschema2shacl b/packages/edb-sparnatural/jsonschema2shacl new file mode 160000 index 00000000..1301ccc8 --- /dev/null +++ b/packages/edb-sparnatural/jsonschema2shacl @@ -0,0 +1 @@ +Subproject commit 1301ccc87dc460eeb56965d2990453d1f2df58a6 diff --git a/packages/edb-sparnatural/package.json b/packages/edb-sparnatural/package.json new file mode 100644 index 00000000..bd0f4b92 --- /dev/null +++ b/packages/edb-sparnatural/package.json @@ -0,0 +1,39 @@ +{ + "name": "@slub/edb-sparnatural", + "version": "1.0.0", + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.js", + "require": "./dist/index.cjs", + "default": "./dist/index.js", + "types": "./dist/index.d.ts" + } + }, + "scripts": { + "build": "tsup src/index.tsx", + "dev": "tsup src/index.tsx", + "lint": "eslint \"**/*.ts*\"", + "lint-fix": "eslint --fix \"**/*.ts*\"", + "jsonschema2shacl:install": "./install-jsonschema2shacl.sh", + "jsonschema2shacl": "./.venv/bin/python3 ./jsonschema2shacl/main.py" + }, + "peerDependencies": { + "react": "^18", + "leaflet": "~1.9" + }, + "dependencies": { + "sparnatural": "^9.5.1", + "select2": "^4.1.0-rc.0", + "@fortawesome/fontawesome-free": "^6.6.0", + "@geoman-io/leaflet-geoman-free": "^2.17.0" + }, + "devDependencies": { + "@slub/edb-build-helper": "workspace:*", + "@slub/edb-tsconfig": "workspace:*", + "@slub/edb-tsup-config": "workspace:*" + } +} diff --git a/packages/edb-sparnatural/src/EdbSparnatural.stories.tsx b/packages/edb-sparnatural/src/EdbSparnatural.stories.tsx new file mode 100644 index 00000000..0b21fecb --- /dev/null +++ b/packages/edb-sparnatural/src/EdbSparnatural.stories.tsx @@ -0,0 +1,34 @@ +import { Meta, StoryObj } from "@storybook/react"; +import { EdbSparnatural } from "./EdbSparnatural"; + +const meta: Meta = { + component: EdbSparnatural, + title: "Components/EdbSparnatural", +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + src: "https://sparnatural.eu/demos/demo-dbpedia-v2/sparnatural-config.ttl", + lang: "en", + endpoint: "https://fr.dbpedia.org/sparql", + distinct: "true", + limit: "100", + prefix: + "skos:http://www.w3.org/2004/02/skos/core# rico:https://www.ica.org/standards/RiC/ontology#", + debug: "true", + }, +}; + +export const WithCustomEndpoint: Story = { + args: { + src: "./schema/Exhibition.schema_shape_ai.ttl", + lang: "en", + endpoint: "http://localhost:7878/query", + distinct: "true", + limit: "100", + prefix: "sladb:http://ontologies.slub-dresden.de/exhibition#", + }, +}; diff --git a/packages/edb-sparnatural/src/EdbSparnatural.tsx b/packages/edb-sparnatural/src/EdbSparnatural.tsx new file mode 100644 index 00000000..2f5939c1 --- /dev/null +++ b/packages/edb-sparnatural/src/EdbSparnatural.tsx @@ -0,0 +1,76 @@ +import React, { useCallback, useEffect, useRef } from "react"; +import "select2/src/scss/core.scss"; +import "sparnatural/src/assets/stylesheets/sparnatural.scss"; +import "leaflet/dist/leaflet.css"; +import "@fortawesome/fontawesome-free/css/all.css"; +import "@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.css"; +export interface SparnaturalEvent extends Event { + detail?: { + queryString: string; + queryJson: string; + querySparqlJs: string; + }; +} +export type EdbSparnaturalProps = { + src: string; + lang: string; + endpoint: string; + distinct: string; + limit: string; + prefix: string; + debug: string; + onQueryUpdated?: (event: SparnaturalEvent) => void; +}; + +export const EdbSparnatural: React.FC = ({ + src, + lang, + endpoint, + distinct, + limit, + prefix, + debug, + onQueryUpdated, +}) => { + const sparnaturalRef = useRef(null); + + const handleQueryUpdated = useCallback( + (event: SparnaturalEvent) => { + try { + onQueryUpdated?.(event); + } catch (e) {} + }, + [onQueryUpdated], + ); + + useEffect(() => { + import("sparnatural").then(() => { + sparnaturalRef.current?.addEventListener( + "queryUpdated", + handleQueryUpdated, + ); + + return () => { + sparnaturalRef.current?.removeEventListener( + "queryUpdated", + handleQueryUpdated, + ); + }; + }); + }, [handleQueryUpdated]); + + return ( + + ); +}; diff --git a/packages/edb-sparnatural/src/declaration.d.ts b/packages/edb-sparnatural/src/declaration.d.ts new file mode 100644 index 00000000..bce4d57d --- /dev/null +++ b/packages/edb-sparnatural/src/declaration.d.ts @@ -0,0 +1,16 @@ +namespace JSX { + interface IntrinsicElements { + "spar-natural": SparnaturalAttributes; + } + + interface SparnaturalAttributes { + ref: React.RefObject; + src: string; + lang: string; + endpoint: string; + distinct: string; + limit: string; + prefix: string; + debug: string; + } +} diff --git a/packages/edb-sparnatural/src/index.tsx b/packages/edb-sparnatural/src/index.tsx new file mode 100644 index 00000000..fbf9d126 --- /dev/null +++ b/packages/edb-sparnatural/src/index.tsx @@ -0,0 +1 @@ +export * from "./EdbSparnatural"; diff --git a/packages/edb-sparnatural/tsconfig.json b/packages/edb-sparnatural/tsconfig.json new file mode 100644 index 00000000..9db70c96 --- /dev/null +++ b/packages/edb-sparnatural/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "@slub/edb-tsconfig/react-library.json", + "include": ["src"], + "exclude": ["dist", "build", "node_modules"], + "compilerOptions": { + "strict": false, + "resolveJsonModule": true + } +} diff --git a/packages/edb-sparnatural/tsup.config.js b/packages/edb-sparnatural/tsup.config.js new file mode 100644 index 00000000..85b8dcc3 --- /dev/null +++ b/packages/edb-sparnatural/tsup.config.js @@ -0,0 +1,5 @@ +import { makeConfigWithExternals } from "@slub/edb-tsup-config/tsup.config.js"; +import pkg from "./package.json"; + +const config = makeConfigWithExternals(pkg); +export default config; diff --git a/packages/file-import/package.json b/packages/file-import/package.json new file mode 100644 index 00000000..0df8200f --- /dev/null +++ b/packages/file-import/package.json @@ -0,0 +1,45 @@ +{ + "name": "@slub/edb-file-import", + "version": "1..0", + "description": "nodejs file RDF file import utilities", + "type": "module", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.js", + "default": "./dist/index.js", + "types": "./dist/index.d.ts" + } + }, + "scripts": { + "build": "tsup", + "dev": "tsup --watch", + "lint": "eslint \"**/*.ts*\"", + "lint-fix": "eslint --fix \"**/*.ts*\"", + "test": "NODE_OPTIONS=--experimental-vm-modules jest --passWithNoTests --color", + "test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch --color", + "test:coverage": "NODE_OPTIONS=--experimental-vm-modules jest --coverage" + }, + "devDependencies": { + "@slub/edb-build-helper": "workspace:*", + "@slub/edb-core-types": "workspace:*", + "@slub/edb-tsconfig": "workspace:*", + "@slub/edb-tsup-config": "workspace:*", + "@rdfjs/types": "^1.1.0", + "@types/jest": "^29.5.12", + "@types/json-schema": "^7.0.14", + "eslint-config-edb": "workspace:*", + "typescript": "^5.3.3" + }, + "dependencies": { + "@slub/edb-maintenance-utils": "workspace:*", + "json-schema": "^0.4.0", + "jsonld": "^8.3.2", + "jsonld-context-parser": "^2.4.0", + "n3": "^1.17.2", + "rdf-dataset-ext": "^1.1.0", + "string-to-stream": "^3.0.1", + "mime-types": "^2.1.35" + } +} diff --git a/packages/file-import/src/index.ts b/packages/file-import/src/index.ts new file mode 100644 index 00000000..ca5d87a2 --- /dev/null +++ b/packages/file-import/src/index.ts @@ -0,0 +1 @@ +export * from "./processEachDocumentFromFile"; diff --git a/packages/file-import/src/processEachDocumentFromFile.ts b/packages/file-import/src/processEachDocumentFromFile.ts new file mode 100644 index 00000000..b3088edd --- /dev/null +++ b/packages/file-import/src/processEachDocumentFromFile.ts @@ -0,0 +1,44 @@ +import { JSONSchema7 } from "json-schema"; +import { + DSProcessingOptions, + processAllDocumentsFromDataset, +} from "@slub/edb-maintenance-utils"; +import mime from "mime-types"; +import { DatasetCore, Quad } from "@rdfjs/types"; +import datasetFactory from "@rdfjs/dataset"; +import N3 from "n3"; +import * as fs from "fs"; +import jsonld from "jsonld"; + +export const processEachDocumentFromFile = async ( + file: string, + schema: JSONSchema7, + onDocument: ( + entityIRI: string, + typeIRI: string, + document: any, + ) => Promise, + options: DSProcessingOptions, +) => { + const mimeType = mime.lookup(file); + let ds: DatasetCore | null = null; + switch (mimeType) { + case "text/turtle": + case "application/n-triples": + const reader = new N3.Parser(); + ds = datasetFactory.dataset(reader.parse(fs.readFileSync(file, "utf-8"))); + break; + case "application/json": + const quads = (await jsonld.toRDF( + JSON.parse(fs.readFileSync(file, "utf-8")), + )) as Quad[]; + ds = datasetFactory.dataset(quads); + break; + default: + throw new Error(`Unsupported file type: ${mimeType}`); + } + if (ds === null) { + throw new Error("Unable to parse the data"); + } + return await processAllDocumentsFromDataset(ds, schema, onDocument, options); +}; diff --git a/packages/file-import/tsconfig.json b/packages/file-import/tsconfig.json new file mode 100644 index 00000000..db5fca43 --- /dev/null +++ b/packages/file-import/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "@slub/edb-tsconfig/base.json", + "include": ["src"], + "exclude": ["dist", "build", "node_modules"], + "compilerOptions": { + "resolveJsonModule": true, + "strict": true, + "lib": ["esnext", "dom"] + } +} diff --git a/packages/file-import/tsup.config.js b/packages/file-import/tsup.config.js new file mode 100644 index 00000000..85b8dcc3 --- /dev/null +++ b/packages/file-import/tsup.config.js @@ -0,0 +1,5 @@ +import { makeConfigWithExternals } from "@slub/edb-tsup-config/tsup.config.js"; +import pkg from "./package.json"; + +const config = makeConfigWithExternals(pkg); +export default config; diff --git a/packages/form-renderer/basic-renderer/package.json b/packages/form-renderer/basic-renderer/package.json new file mode 100644 index 00000000..207407aa --- /dev/null +++ b/packages/form-renderer/basic-renderer/package.json @@ -0,0 +1,34 @@ +{ + "name": "@slub/edb-basic-renderer", + "version": "1.0.0", + "private": true, + "main": "src/index.tsx", + "types": "src/index.tsx", + "sideEffects": false, + "scripts": { + "typecheck": "tsc -b", + "lint": "eslint \"**/*.ts*\"", + "lint-fix": "eslint --fix \"**/*.ts*\"" + }, + "peerDependencies": { + "@mui/material": "^5", + "@mui/icons-material": "^5", + "@jsonforms/material-renderers": "^3", + "@jsonforms/core": "^3", + "@jsonforms/react": "^3", + "react": "^18" + }, + "dependencies": { + "@slub/edb-core-utils": "workspace:*", + "next-i18next": "^15", + "lodash-es": "^4.17", + "mui-image": "^1.0.7" + }, + "devDependencies": { + "@types/react": "^18.3.3", + "@types/lodash-es": "^4.17.12", + "@jsonforms/core": "^3", + "@jsonforms/react": "^3" + } +} + diff --git a/apps/exhibition-live/components/renderer/AutoIdentifierRenderer.stories.tsx b/packages/form-renderer/basic-renderer/src/AutoIdentifierRenderer.stories.tsx similarity index 90% rename from apps/exhibition-live/components/renderer/AutoIdentifierRenderer.stories.tsx rename to packages/form-renderer/basic-renderer/src/AutoIdentifierRenderer.stories.tsx index 97b68e54..3774eb5d 100644 --- a/apps/exhibition-live/components/renderer/AutoIdentifierRenderer.stories.tsx +++ b/packages/form-renderer/basic-renderer/src/AutoIdentifierRenderer.stories.tsx @@ -6,10 +6,10 @@ import { import { JsonForms } from "@jsonforms/react"; import { useCallback, useState } from "react"; -import AutoIdentifierRenderer from "./AutoIdentifierRenderer"; +import { AutoIdentifierRenderer } from "./AutoIdentifierRenderer"; export default { - title: "form/exhibition/AutoIdentifierRenderer", + title: "ui/form/renderer/AutoIdentifierRenderer", component: AutoIdentifierRenderer, }; diff --git a/apps/exhibition-live/components/renderer/AutoIdentifierRenderer.tsx b/packages/form-renderer/basic-renderer/src/AutoIdentifierRenderer.tsx similarity index 71% rename from apps/exhibition-live/components/renderer/AutoIdentifierRenderer.tsx rename to packages/form-renderer/basic-renderer/src/AutoIdentifierRenderer.tsx index d6aa81bc..f58efdbe 100644 --- a/apps/exhibition-live/components/renderer/AutoIdentifierRenderer.tsx +++ b/packages/form-renderer/basic-renderer/src/AutoIdentifierRenderer.tsx @@ -1,6 +1,6 @@ import { ControlProps, showAsRequired } from "@jsonforms/core"; import { withJsonFormsControlProps } from "@jsonforms/react"; -import { Edit, EditOff, Visibility, VisibilityOff } from "@mui/icons-material"; +import { Visibility, VisibilityOff } from "@mui/icons-material"; import { FormControl, FormLabel, @@ -9,12 +9,10 @@ import { IconButton, } from "@mui/material"; import merge from "lodash/merge"; -import React, { useCallback, useEffect, useState } from "react"; -import { v4 as uuidv4 } from "uuid"; -import { useSettings } from "../state/useLocalSettings"; -import { slent } from "../form/formConfigs"; +import React, { useCallback, useState } from "react"; +import { useSettings } from "@slub/edb-state-hooks"; -const AutoIdentifierRenderer = (props: ControlProps) => { +const AutoIdentifierRendererComponent = (props: ControlProps) => { const { id, errors, @@ -38,14 +36,6 @@ const AutoIdentifierRenderer = (props: ControlProps) => { [path, handleChange], ); - useEffect(() => { - if (!data && schema.title) { - const prefix = slent[""].value; - const newURI = `${prefix}${uuidv4()}`; - handleChange_(newURI); - } - }, [schema, data, handleChange_]); - const { features: { enableDebug }, } = useSettings(); @@ -55,7 +45,6 @@ const AutoIdentifierRenderer = (props: ControlProps) => { ({ marginBottom: theme.spacing(2) })} > @@ -83,4 +72,6 @@ const AutoIdentifierRenderer = (props: ControlProps) => { ); }; -export default withJsonFormsControlProps(AutoIdentifierRenderer); +export const AutoIdentifierRenderer = withJsonFormsControlProps( + AutoIdentifierRendererComponent, +); diff --git a/packages/form-renderer/basic-renderer/src/EnumRenderer.tsx b/packages/form-renderer/basic-renderer/src/EnumRenderer.tsx new file mode 100644 index 00000000..681eeae1 --- /dev/null +++ b/packages/form-renderer/basic-renderer/src/EnumRenderer.tsx @@ -0,0 +1,55 @@ +import { JsonSchema } from "@jsonforms/core"; +import { withJsonFormsControlProps } from "@jsonforms/react"; +import FormControl from "@mui/material/FormControl"; +import FormControlLabel from "@mui/material/FormControlLabel"; +import FormLabel from "@mui/material/FormLabel"; +import Hidden from "@mui/material/Hidden"; +import Radio from "@mui/material/Radio"; +import RadioGroup from "@mui/material/RadioGroup"; +import React from "react"; +import { useTranslation } from "next-i18next"; + +type EnumRendererProps = { + data: any; + handleChange(path: string, value: any): void; + path: string; + label: string; + schema: JsonSchema; + visible?: boolean; +}; + +const EnumRendererComponent = ({ + data, + handleChange, + path, + label, + schema, + visible, +}: EnumRendererProps) => { + const { t } = useTranslation(); + + return ( + + + {t(label)} + handleChange(path, ev.target.value)} + aria-labelledby={`enum-label-${path}`} + sx={{ flexDirection: "row" }} + > + {(schema.enum || []).map((value) => ( + } + label={`${t(value)}`} + /> + ))} + + + + ); +}; + +export const EnumRenderer = withJsonFormsControlProps(EnumRendererComponent); diff --git a/apps/exhibition-live/components/renderer/ImageRenderer.tsx b/packages/form-renderer/basic-renderer/src/ImageRenderer.tsx similarity index 92% rename from apps/exhibition-live/components/renderer/ImageRenderer.tsx rename to packages/form-renderer/basic-renderer/src/ImageRenderer.tsx index 3e5be2d6..05e5a9ff 100644 --- a/apps/exhibition-live/components/renderer/ImageRenderer.tsx +++ b/packages/form-renderer/basic-renderer/src/ImageRenderer.tsx @@ -13,7 +13,7 @@ import merge from "lodash/merge"; import React, { useCallback, useState } from "react"; import { useTranslation } from "next-i18next"; -const ImageRenderer = (props: ControlProps) => { +const ImageRendererComponent = (props: ControlProps) => { const { id, errors, @@ -43,7 +43,6 @@ const ImageRenderer = (props: ControlProps) => { ({ marginBottom: theme.spacing(2) })} > @@ -58,7 +57,6 @@ const ImageRenderer = (props: ControlProps) => { handleChange_(e.target.value)} value={data} fullWidth={true} @@ -80,4 +78,4 @@ const ImageRenderer = (props: ControlProps) => { ); }; -export default withJsonFormsControlProps(ImageRenderer); +export const ImageRenderer = withJsonFormsControlProps(ImageRendererComponent); diff --git a/apps/exhibition-live/components/renderer/MaterialBooleanControl.tsx b/packages/form-renderer/basic-renderer/src/MaterialBooleanControlRenderer.tsx similarity index 80% rename from apps/exhibition-live/components/renderer/MaterialBooleanControl.tsx rename to packages/form-renderer/basic-renderer/src/MaterialBooleanControlRenderer.tsx index a383c39b..8bc36ff0 100644 --- a/apps/exhibition-live/components/renderer/MaterialBooleanControl.tsx +++ b/packages/form-renderer/basic-renderer/src/MaterialBooleanControlRenderer.tsx @@ -1,19 +1,12 @@ import isEmpty from "lodash/isEmpty"; import React, { useCallback } from "react"; -import { - isBooleanControl, - RankedTester, - rankWith, - ControlProps, - CellProps, - WithClassname, -} from "@jsonforms/core"; +import { CellProps, ControlProps, WithClassname } from "@jsonforms/core"; import { withJsonFormsControlProps } from "@jsonforms/react"; import { Checkbox, FormControlLabel, Hidden } from "@mui/material"; import merge from "lodash/merge"; import isNil from "lodash/isNil"; -export const MuiCheckbox = React.memo((props: CellProps & WithClassname) => { +const MuiCheckbox = React.memo((props: CellProps & WithClassname) => { const { data, className, id, enabled, uischema, path, handleChange, config } = props; const appliedUiSchemaOptions = merge({}, config, uischema.options); @@ -38,7 +31,7 @@ export const MuiCheckbox = React.memo((props: CellProps & WithClassname) => { /> ); }); -export const MaterialBooleanControl = ({ +const MaterialBooleanControl = ({ data, visible, label, @@ -78,8 +71,6 @@ export const MaterialBooleanControl = ({ ); }; -export const materialBooleanControlTester: RankedTester = rankWith( - 5, - isBooleanControl, +export const MaterialBooleanControlRenderer = withJsonFormsControlProps( + MaterialBooleanControl, ); -export default withJsonFormsControlProps(MaterialBooleanControl); diff --git a/packages/form-renderer/basic-renderer/src/MaterialDateRenderer.tsx b/packages/form-renderer/basic-renderer/src/MaterialDateRenderer.tsx new file mode 100644 index 00000000..cb64d177 --- /dev/null +++ b/packages/form-renderer/basic-renderer/src/MaterialDateRenderer.tsx @@ -0,0 +1,94 @@ +import { ControlProps, isDescriptionHidden } from "@jsonforms/core"; +import { + createOnChangeHandler, + getData, + useFocus, +} from "@jsonforms/material-renderers"; +import { withJsonFormsControlProps } from "@jsonforms/react"; +import { DatePicker } from "@mui/lab"; +import { FormHelperText, Hidden, TextField } from "@mui/material"; +import merge from "lodash/merge"; +import React, { useMemo } from "react"; +import { useTranslation } from "next-i18next"; + +const MaterialDateControl = (props: ControlProps) => { + const [focused, onFocus, onBlur] = useFocus(); + const { + description, + id, + errors, + label, + uischema, + visible, + enabled, + required, + path, + handleChange, + data, + config, + } = props; + const isValid = errors.length === 0; + const appliedUiSchemaOptions = merge({}, config, uischema.options); + const showDescription = !isDescriptionHidden( + visible, + description, + focused, + appliedUiSchemaOptions.showUnfocusedDescription, + ); + + const { t } = useTranslation(); + const format = appliedUiSchemaOptions.dateFormat ?? t("date_format"); + const saveFormat = appliedUiSchemaOptions.dateSaveFormat ?? "YYYY-MM-DD"; + + const firstFormHelperText = showDescription + ? description + : !isValid + ? errors + : null; + const secondFormHelperText = showDescription && !isValid ? errors : null; + const onChange = useMemo( + () => createOnChangeHandler(path, handleChange, saveFormat), + [path, handleChange, saveFormat], + ); + + return ( + + d && onChange(d)} + inputFormat={format} + disableMaskedInput + views={appliedUiSchemaOptions.views} + disabled={!enabled} + cancelText={appliedUiSchemaOptions.cancelLabel} + clearText={appliedUiSchemaOptions.clearLabel} + okText={appliedUiSchemaOptions.okLabel} + // @ts-ignore + renderInput={(params) => ( + + )} + /> + + {firstFormHelperText} + + {secondFormHelperText} + + ); +}; + +export const MaterialDateRenderer = + withJsonFormsControlProps(MaterialDateControl); diff --git a/apps/exhibition-live/components/renderer/TypeOfRenderer.tsx b/packages/form-renderer/basic-renderer/src/TypeOfRenderer.tsx similarity index 89% rename from apps/exhibition-live/components/renderer/TypeOfRenderer.tsx rename to packages/form-renderer/basic-renderer/src/TypeOfRenderer.tsx index c833c94e..18d3ae32 100644 --- a/apps/exhibition-live/components/renderer/TypeOfRenderer.tsx +++ b/packages/form-renderer/basic-renderer/src/TypeOfRenderer.tsx @@ -8,11 +8,10 @@ import { Hidden, IconButton, } from "@mui/material"; -import merge from "lodash/merge"; +import merge from "lodash-es/merge"; import React, { useCallback, useEffect, useState } from "react"; -import { v4 as uuidv4 } from "uuid"; -const TypeOfRenderer = (props: ControlProps) => { +const TypeOfRendererComponent = (props: ControlProps) => { const { id, errors, @@ -48,7 +47,6 @@ const TypeOfRenderer = (props: ControlProps) => { ({ marginBottom: theme.spacing(2) })} > @@ -76,4 +74,6 @@ const TypeOfRenderer = (props: ControlProps) => { ); }; -export default withJsonFormsControlProps(TypeOfRenderer); +export const TypeOfRenderer = withJsonFormsControlProps( + TypeOfRendererComponent, +); diff --git a/packages/form-renderer/basic-renderer/src/index.tsx b/packages/form-renderer/basic-renderer/src/index.tsx new file mode 100644 index 00000000..4997db29 --- /dev/null +++ b/packages/form-renderer/basic-renderer/src/index.tsx @@ -0,0 +1,9 @@ +export * from "./ImageRenderer"; +export * from "./EnumRenderer"; +export * from "./TypeOfRenderer"; +export * from "./special-date"; +export * from "./MaterialBooleanControlRenderer"; +export * from "./materialBooleanControlTester"; +export * from "./MaterialDateRenderer"; +export * from "./materialDateRendererTester"; +export * from "./AutoIdentifierRenderer"; diff --git a/packages/form-renderer/basic-renderer/src/materialBooleanControlTester.ts b/packages/form-renderer/basic-renderer/src/materialBooleanControlTester.ts new file mode 100644 index 00000000..c3a9815a --- /dev/null +++ b/packages/form-renderer/basic-renderer/src/materialBooleanControlTester.ts @@ -0,0 +1,6 @@ +import { isBooleanControl, RankedTester, rankWith } from "@jsonforms/core"; + +export const materialBooleanControlTester: RankedTester = rankWith( + 5, + isBooleanControl, +); diff --git a/packages/form-renderer/basic-renderer/src/materialDateRendererTester.ts b/packages/form-renderer/basic-renderer/src/materialDateRendererTester.ts new file mode 100644 index 00000000..49f44a0a --- /dev/null +++ b/packages/form-renderer/basic-renderer/src/materialDateRendererTester.ts @@ -0,0 +1,6 @@ +import { isDateControl, RankedTester, rankWith } from "@jsonforms/core"; + +export const materialDateRendererTester: RankedTester = rankWith( + 6, + isDateControl, +); diff --git a/packages/form-renderer/basic-renderer/src/special-date/AdbSpecialDate.stories.tsx b/packages/form-renderer/basic-renderer/src/special-date/AdbSpecialDate.stories.tsx new file mode 100644 index 00000000..8d8e92cb --- /dev/null +++ b/packages/form-renderer/basic-renderer/src/special-date/AdbSpecialDate.stories.tsx @@ -0,0 +1,39 @@ +import { useState } from "react"; +import { Meta, StoryObj } from "@storybook/react"; +import { AdbSpecialDateFormGroup } from "./AdbSpecialDateFormGroup"; + +export default { + title: "ui/form/renderer/AdbSpecialDateFormGroup", + component: AdbSpecialDateFormGroup, + argTypes: { + data: { control: false }, + handleChange: { control: false }, + disabled: { control: "boolean" }, + }, +} as Meta; + +const AutocompleteSpecialDateFormGroupStory = ({ + disabled, +}: { + disabled: boolean; +}) => { + const [data, setData] = useState(); + return ( + + ); +}; + +type Story = StoryObj; + +export const AdbSpecialDateFormPrimary: Story = { + render: (args) => ( + + ), + args: { + disabled: false, + }, +}; diff --git a/packages/form-renderer/basic-renderer/src/special-date/AdbSpecialDateFormGroup.tsx b/packages/form-renderer/basic-renderer/src/special-date/AdbSpecialDateFormGroup.tsx new file mode 100644 index 00000000..4df068d6 --- /dev/null +++ b/packages/form-renderer/basic-renderer/src/special-date/AdbSpecialDateFormGroup.tsx @@ -0,0 +1,92 @@ +import { FormGroup, FormGroupProps, TextField } from "@mui/material"; +import React, { useCallback } from "react"; +import { + getDatePart, + getDatePartAsString, + getPaddedDatePart, + leftpad, +} from "@slub/edb-core-utils"; + +export type AdbSpecialDateFormGroupProps = { + data?: number; + handleChange: (value: number) => void; + disabled?: boolean; +}; +export const AdbSpecialDateFormGroup = ({ + data, + handleChange, + disabled, + ...props +}: AdbSpecialDateFormGroupProps & FormGroupProps) => { + const handleTextFieldChange = useCallback( + ( + event: React.ChangeEvent, + field: "day" | "month" | "year", + ) => { + const maxLength = field === "year" ? 4 : 2, + maxValue = field === "year" ? 9999 : field === "month" ? 12 : 31, + newValueNumber = Number(event.target.value); + if (isNaN(newValueNumber) || newValueNumber > maxValue) return; + const newValue = String(newValueNumber); + if (newValue.length > maxLength) return; + let strData, paddedValue; + try { + paddedValue = leftpad(newValueNumber, maxLength); + } catch (e) { + return; + } + + // check if the day is valid, if not, set it to the last day of the month (and handle leap years) + let changeDay = + field === "day" ? paddedValue : getPaddedDatePart(data, "day"); + const currentMonth = getDatePart(data, "month"), + currentYear = getDatePart(data, "year"); + if (currentMonth > 0) { + const lastDayOfMonth = new Date( + currentYear ?? 4, + currentMonth, + 0, + ).getDate(); + if (Number(changeDay) > lastDayOfMonth) { + changeDay = leftpad(lastDayOfMonth, 2); + } + } + if (field === "day") + strData = + getPaddedDatePart(data, "year") + + getPaddedDatePart(data, "month") + + changeDay; + else if (field === "month") + strData = getPaddedDatePart(data, "year") + paddedValue + changeDay; + else strData = paddedValue + getPaddedDatePart(data, "month") + changeDay; + handleChange(Number(strData)); + }, + [handleChange, data], + ); + + return ( + + handleTextFieldChange(e, "day")} + /> + handleTextFieldChange(e, "month")} + label={"Monat"} + value={getDatePartAsString(data ?? 0, "month")} + /> + handleTextFieldChange(e, "year")} + label={"Jahr"} + value={getDatePartAsString(data ?? 0, "year")} + /> + + ); +}; diff --git a/packages/form-renderer/basic-renderer/src/special-date/AdbSpecialDateRenderer.tsx b/packages/form-renderer/basic-renderer/src/special-date/AdbSpecialDateRenderer.tsx new file mode 100644 index 00000000..02626d7c --- /dev/null +++ b/packages/form-renderer/basic-renderer/src/special-date/AdbSpecialDateRenderer.tsx @@ -0,0 +1,61 @@ +import { ControlProps, isDescriptionHidden } from "@jsonforms/core"; +import { useFocus } from "@jsonforms/material-renderers"; +import { withJsonFormsControlProps } from "@jsonforms/react"; +import { FormControl, FormHelperText, FormLabel, Hidden } from "@mui/material"; +import React, { useMemo } from "react"; +import { AdbSpecialDateFormGroup } from "./AdbSpecialDateFormGroup"; + +const AdbSpecialDateControlComponent = (props: ControlProps) => { + const [focused] = useFocus(); + const { + description, + errors, + label, + visible, + enabled, + path, + handleChange, + data, + } = props; + const isValid = errors.length === 0; + //const appliedUiSchemaOptions = merge({}, config, uischema.options) + const showDescription = !isDescriptionHidden( + visible, + description, + focused, + true, + ); + + const firstFormHelperText = showDescription + ? description + : !isValid + ? errors + : null; + const secondFormHelperText = showDescription && !isValid ? errors : null; + + const numberData = useMemo(() => { + const num = Number(data); + return isNaN(num) ? undefined : num; + }, [data]); + + return ( + + + {label && label.length > 0 && {label}} + handleChange(path, value)} + disabled={!enabled} + /> + + {firstFormHelperText} + + {secondFormHelperText} + + + ); +}; + +export const AdbSpecialDateRenderer = withJsonFormsControlProps( + AdbSpecialDateControlComponent, +); diff --git a/packages/form-renderer/basic-renderer/src/special-date/adbSpecialDateControlTester.ts b/packages/form-renderer/basic-renderer/src/special-date/adbSpecialDateControlTester.ts new file mode 100644 index 00000000..6d66580a --- /dev/null +++ b/packages/form-renderer/basic-renderer/src/special-date/adbSpecialDateControlTester.ts @@ -0,0 +1,13 @@ +import { + and, + isIntegerControl, + or, + RankedTester, + rankWith, + scopeEndsWith, +} from "@jsonforms/core"; + +export const adbSpecialDateControlTester: RankedTester = rankWith( + 6, + and(isIntegerControl, or(scopeEndsWith("dateValue"), scopeEndsWith("Date"))), +); diff --git a/packages/form-renderer/basic-renderer/src/special-date/index.ts b/packages/form-renderer/basic-renderer/src/special-date/index.ts new file mode 100644 index 00000000..a6ca05a0 --- /dev/null +++ b/packages/form-renderer/basic-renderer/src/special-date/index.ts @@ -0,0 +1,2 @@ +export * from "./AdbSpecialDateRenderer"; +export * from "./adbSpecialDateControlTester"; diff --git a/packages/form-renderer/basic-renderer/tsconfig.json b/packages/form-renderer/basic-renderer/tsconfig.json new file mode 100644 index 00000000..9db70c96 --- /dev/null +++ b/packages/form-renderer/basic-renderer/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "@slub/edb-tsconfig/react-library.json", + "include": ["src"], + "exclude": ["dist", "build", "node_modules"], + "compilerOptions": { + "strict": false, + "resolveJsonModule": true + } +} diff --git a/packages/form-renderer/layout-renderer/package.json b/packages/form-renderer/layout-renderer/package.json new file mode 100644 index 00000000..7092e416 --- /dev/null +++ b/packages/form-renderer/layout-renderer/package.json @@ -0,0 +1,34 @@ +{ + "name": "@slub/edb-layout-renderer", + "version": "1.0.0", + "private": true, + "main": "src/index.tsx", + "types": "src/index.tsx", + "sideEffects": false, + "scripts": { + "typecheck": "tsc -b", + "lint": "eslint \"**/*.ts*\"", + "lint-fix": "eslint --fix \"**/*.ts*\"" + }, + "peerDependencies": { + "@mui/material": "^5", + "@mui/icons-material": "^5", + "@jsonforms/material-renderers": "^3", + "@jsonforms/core": "^3", + "@jsonforms/react": "^3", + "react": "^18" + }, + "dependencies": { + "@slub/edb-ui-utils": "workspace:*", + "next-i18next": "^15", + "lodash-es": "^4.17", + "mui-image": "^1.0.7" + }, + "devDependencies": { + "@types/react": "^18.3.3", + "@types/lodash-es": "^4.17.12", + "@jsonforms/core": "^3", + "@jsonforms/react": "^3" + } +} + diff --git a/apps/exhibition-live/components/renderer/CombinatorProperties.tsx b/packages/form-renderer/layout-renderer/src/CombinatorProperties.tsx similarity index 94% rename from apps/exhibition-live/components/renderer/CombinatorProperties.tsx rename to packages/form-renderer/layout-renderer/src/CombinatorProperties.tsx index fefc4fcc..d47eeaa3 100644 --- a/apps/exhibition-live/components/renderer/CombinatorProperties.tsx +++ b/packages/form-renderer/layout-renderer/src/CombinatorProperties.tsx @@ -1,6 +1,6 @@ import { Generate, JsonSchema, Layout, UISchemaElement } from "@jsonforms/core"; import { JsonFormsDispatch } from "@jsonforms/react"; -import omit from "lodash/omit"; +import omit from "lodash-es/omit"; import React from "react"; interface CombinatorPropertiesProps { @@ -45,5 +45,3 @@ export class CombinatorProperties extends React.Component< return null; } } - -export default CombinatorProperties; diff --git a/apps/exhibition-live/components/renderer/MaterialCategorizationStepperLayoutWithPortal.tsx b/packages/form-renderer/layout-renderer/src/MaterialCategorizationStepperLayoutWithPortal.tsx similarity index 96% rename from apps/exhibition-live/components/renderer/MaterialCategorizationStepperLayoutWithPortal.tsx rename to packages/form-renderer/layout-renderer/src/MaterialCategorizationStepperLayoutWithPortal.tsx index 06ca34a7..79b96f1b 100644 --- a/apps/exhibition-live/components/renderer/MaterialCategorizationStepperLayoutWithPortal.tsx +++ b/packages/form-renderer/layout-renderer/src/MaterialCategorizationStepperLayoutWithPortal.tsx @@ -1,5 +1,5 @@ import React, { ComponentType, useCallback, useState } from "react"; -import merge from "lodash/merge"; +import merge from "lodash-es/merge"; import { Box, Button, @@ -30,9 +30,9 @@ import { MaterialLayoutRenderer, MaterialLayoutRendererProps, } from "@jsonforms/material-renderers"; -import { optionallyCreatePortal } from "../helper/optionallyCreatePortal"; import { KeyboardArrowLeft, KeyboardArrowRight } from "@mui/icons-material"; import { useTranslation } from "next-i18next"; +import { optionallyCreatePortal } from "@slub/edb-ui-utils"; export const materialCategorizationStepperTester: RankedTester = rankWith( 4, @@ -87,7 +87,7 @@ export const MaterialCategorizationStepperLayout = ( marginRight: "1em", }; const categories = categorization.elements.filter((category: Category) => - isVisible(category, data, undefined, ajv), + isVisible(category, data, undefined, ajv as any), ); const { t } = useTranslation(); const childProps: MaterialLayoutRendererProps = { @@ -222,7 +222,7 @@ const withAjvProps = ) => (props: P) => { const ctx = useJsonForms(); - const ajv = getAjv({ jsonforms: { ...ctx } }); + const ajv = getAjv({ jsonforms: { ...ctx } }) as unknown as AjvProps["ajv"]; return ; }; diff --git a/apps/exhibition-live/components/renderer/MaterialCustomAnyOfRenderer.tsx b/packages/form-renderer/layout-renderer/src/MaterialCustomAnyOfRenderer.tsx similarity index 87% rename from apps/exhibition-live/components/renderer/MaterialCustomAnyOfRenderer.tsx rename to packages/form-renderer/layout-renderer/src/MaterialCustomAnyOfRenderer.tsx index 6dd29ca4..763352cb 100644 --- a/apps/exhibition-live/components/renderer/MaterialCustomAnyOfRenderer.tsx +++ b/packages/form-renderer/layout-renderer/src/MaterialCustomAnyOfRenderer.tsx @@ -1,18 +1,15 @@ import { CombinatorKeyword, createCombinatorRenderInfos, - isAnyOfControl, JsonSchema, - RankedTester, - rankWith, + OwnPropsOfControl, resolveSchema, StatePropsOfCombinator, } from "@jsonforms/core"; import { JsonFormsDispatch, withJsonFormsAnyOfProps } from "@jsonforms/react"; import { Hidden, Tab, Tabs } from "@mui/material"; import React, { useCallback, useMemo, useState } from "react"; - -import CombinatorProperties from "./CombinatorProperties"; +import { CombinatorProperties } from "./CombinatorProperties"; export const resolveSubSchemas = ( schema: JsonSchema, @@ -35,7 +32,7 @@ export const resolveSubSchemas = ( }; const anyOf = "anyOf"; -export const MaterialCustomAnyOfRenderer = ({ +const MaterialCustomAnyOfRendererComponent = ({ schema, rootSchema, indexOfFittingSchema, @@ -96,9 +93,9 @@ export const MaterialCustomAnyOfRenderer = ({ ); }; -export const materialCustomAnyOfControlTester: RankedTester = rankWith( - 5, - isAnyOfControl, +export const MaterialCustomAnyOfRenderer: + | React.ComponentClass + | React.FunctionComponent = withJsonFormsAnyOfProps( + // @ts-ignore + MaterialCustomAnyOfRendererComponent, ); - -export default withJsonFormsAnyOfProps(MaterialCustomAnyOfRenderer); diff --git a/apps/exhibition-live/components/renderer/MaterialCustomOnyOfRenderer.stories.tsx b/packages/form-renderer/layout-renderer/src/MaterialCustomOnyOfRenderer.stories.tsx similarity index 86% rename from apps/exhibition-live/components/renderer/MaterialCustomOnyOfRenderer.stories.tsx rename to packages/form-renderer/layout-renderer/src/MaterialCustomOnyOfRenderer.stories.tsx index 90aa0bc2..887110d8 100644 --- a/apps/exhibition-live/components/renderer/MaterialCustomOnyOfRenderer.stories.tsx +++ b/packages/form-renderer/layout-renderer/src/MaterialCustomOnyOfRenderer.stories.tsx @@ -5,13 +5,11 @@ import { } from "@jsonforms/material-renderers"; import { JsonForms } from "@jsonforms/react"; import { useCallback, useState } from "react"; - -import MaterialCustomAnyOfRenderer, { - materialCustomAnyOfControlTester, -} from "./MaterialCustomAnyOfRenderer"; +import { MaterialCustomAnyOfRenderer } from "./MaterialCustomAnyOfRenderer"; +import { materialCustomAnyOfControlTester } from "./materialCustomAnyOfControlTester"; export default { - title: "form/exhibition/MaterialCustomAnyOfRenderer", + title: "ui/form/renderer/MaterialCustomAnyOfRenderer", component: MaterialCustomAnyOfRenderer, }; diff --git a/packages/form-renderer/layout-renderer/src/index.tsx b/packages/form-renderer/layout-renderer/src/index.tsx new file mode 100644 index 00000000..5bb2ca21 --- /dev/null +++ b/packages/form-renderer/layout-renderer/src/index.tsx @@ -0,0 +1,4 @@ +export * from "./CombinatorProperties"; +export * from "./MaterialCustomAnyOfRenderer"; +export * from "./MaterialCategorizationStepperLayoutWithPortal"; +export * from "./materialCustomAnyOfControlTester"; diff --git a/packages/form-renderer/layout-renderer/src/materialCustomAnyOfControlTester.ts b/packages/form-renderer/layout-renderer/src/materialCustomAnyOfControlTester.ts new file mode 100644 index 00000000..7d850af7 --- /dev/null +++ b/packages/form-renderer/layout-renderer/src/materialCustomAnyOfControlTester.ts @@ -0,0 +1,6 @@ +import { isAnyOfControl, RankedTester, rankWith } from "@jsonforms/core"; + +export const materialCustomAnyOfControlTester: RankedTester = rankWith( + 5, + isAnyOfControl, +); diff --git a/packages/form-renderer/layout-renderer/tsconfig.json b/packages/form-renderer/layout-renderer/tsconfig.json new file mode 100644 index 00000000..9db70c96 --- /dev/null +++ b/packages/form-renderer/layout-renderer/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "@slub/edb-tsconfig/react-library.json", + "include": ["src"], + "exclude": ["dist", "build", "node_modules"], + "compilerOptions": { + "strict": false, + "resolveJsonModule": true + } +} diff --git a/packages/form-renderer/linked-data-renderer/package.json b/packages/form-renderer/linked-data-renderer/package.json new file mode 100644 index 00000000..30d21db0 --- /dev/null +++ b/packages/form-renderer/linked-data-renderer/package.json @@ -0,0 +1,45 @@ +{ + "name": "@slub/edb-linked-data-renderer", + "version": "1.0.0", + "private": true, + "main": "src/index.tsx", + "types": "src/index.tsx", + "sideEffects": false, + "scripts": { + "typecheck": "tsc -b", + "lint": "eslint \"**/*.ts*\"", + "lint-fix": "eslint --fix \"**/*.ts*\"" + }, + "peerDependencies": { + "@mui/material": "^5", + "@mui/icons-material": "^5", + "@jsonforms/material-renderers": "^3", + "@jsonforms/core": "^3", + "@jsonforms/react": "^3", + "react": "^18" + }, + "dependencies": { + "@slub/edb-state-hooks": "workspace:*", + "@slub/edb-core-types": "workspace:*", + "@slub/edb-basic-components": "workspace:*", + "@slub/edb-advanced-components": "workspace:*", + "@slub/edb-global-types": "workspace:*", + "@slub/edb-ui-utils": "workspace:*", + "@slub/edb-data-mapping": "workspace:*", + "@slub/json-schema-utils": "workspace:*", + "next-i18next": "^15.3.0", + "json-schema": "^0.4.0", + "lodash": "^4.17.21", + "notistack": "^3.0.1", + "ajv": "^8.14.0", + "json-schema-to-ts": "^3.1.0", + "@ebay/nice-modal-react": "^1.2.13", + "dot": "2.0.0-beta.1" + }, + "devDependencies": { + "@types/react": "^18.3.3", + "@types/lodash": "^4.17.4", + "@types/mui-image": "^1.0.5" + } +} + diff --git a/packages/form-renderer/linked-data-renderer/src/ArrayToolbar.tsx b/packages/form-renderer/linked-data-renderer/src/ArrayToolbar.tsx new file mode 100644 index 00000000..a79c2ad4 --- /dev/null +++ b/packages/form-renderer/linked-data-renderer/src/ArrayToolbar.tsx @@ -0,0 +1,252 @@ +import { + Box, + Grid, + IconButton, + TextField, + Tooltip, + Typography, +} from "@mui/material"; +import * as React from "react"; +import { useTranslation } from "next-i18next"; + +import { useCallback, useMemo } from "react"; +import { JsonSchema7 } from "@jsonforms/core"; +import { + useAdbContext, + useGlobalSearchWithHelper, + useKeyEventForSimilarityFinder, + useRightDrawerState, +} from "@slub/edb-state-hooks"; +import { JSONSchema7 } from "json-schema"; +import { AutocompleteSuggestion } from "@slub/edb-core-types"; +import { NoteAdd } from "@mui/icons-material"; +import { PrimaryField, PrimaryFieldDeclaration } from "@slub/edb-core-types"; +import { SearchbarWithFloatingButton } from "@slub/edb-basic-components"; +import { DiscoverAutocompleteInput } from "@slub/edb-advanced-components"; +import { KnowledgeSources } from "@slub/edb-global-types"; + +export interface ArrayLayoutToolbarProps { + label: string; + errors: string; + path: string; + + enabled?: boolean; + + labelAsHeadline?: boolean; + + addItem(path: string, data: any): () => void; + + createDefault(): any; + + readonly?: boolean; + typeIRI?: string; + onCreate?: () => void; + isReifiedStatement?: boolean; + additionalKnowledgeSources?: string[]; +} + +const getDefaultLabelKey = ( + typeName: string, + primaryFields: PrimaryFieldDeclaration, +) => { + const fieldDefinitions = primaryFields[typeName] as PrimaryField | undefined; + return fieldDefinitions?.label || "title"; +}; +export const ArrayLayoutToolbar = ({ + label, + labelAsHeadline, + errors, + addItem, + enabled, + path, + schema, + readonly, + onCreate, + isReifiedStatement, + formsPath, + additionalKnowledgeSources, +}: ArrayLayoutToolbarProps & { + schema?: JsonSchema7; + formsPath?: string; +}) => { + const { + createEntityIRI, + queryBuildOptions: { primaryFields }, + typeIRIToTypeName, + components: { SimilarityFinder }, + } = useAdbContext(); + const { t } = useTranslation(); + const typeIRI = useMemo(() => schema?.properties?.["@type"]?.const, [schema]); + const typeName = useMemo( + () => typeIRIToTypeName(typeIRI), + [typeIRI, typeIRIToTypeName], + ); + const handleSelectedChange = React.useCallback( + (v: AutocompleteSuggestion) => { + if (!v) return; + addItem(path, { + "@id": v.value, + __label: v.label, + })(); + }, + [addItem, path], + ); + const handleCreateNewFromSearch = React.useCallback( + (value?: string) => { + if (!value) return; + addItem(path, { + "@id": createEntityIRI(typeName), + "@type": typeIRI, + __draft: true, + [getDefaultLabelKey(typeName, primaryFields)]: value, + })(); + }, + [addItem, path, typeName, typeIRI, primaryFields], + ); + const handleEntityIRIChange = useCallback( + (iri: string) => { + handleSelectedChange({ value: iri, label: iri }); + }, + [handleSelectedChange], + ); + + const handleExistingEntityAccepted = useCallback( + (iri: string, data: any) => { + console.log("onExistingEntityAccepted", { iri, data }); + const label = + data[getDefaultLabelKey(typeName, primaryFields)] || data.label || iri; + //handleSelectedChange({ value: iri, label }); + addItem(path, data)(); + inputRef.current?.focus(); + }, + [addItem, typeName], + ); + + const handleMappedDataAccepted = useCallback( + (newData: any) => { + addItem(path, newData)(); + inputRef.current?.focus(); + }, + [addItem, path], + ); + + const { open: sidebarOpen } = useRightDrawerState(); + + const inputRef = React.useRef(null); + const { + path: globalPath, + searchString, + handleSearchStringChange, + handleMappedData, + handleFocus, + isActive, + } = useGlobalSearchWithHelper( + typeName, + typeIRI, + schema as JSONSchema7, + formsPath, + handleMappedDataAccepted, + ); + + const handleKeyUp = useKeyEventForSimilarityFinder(); + const { keepMounted } = useRightDrawerState(); + + return ( + + {(isReifiedStatement || labelAsHeadline) && ( + + {label} + + )} + + {(keepMounted || sidebarOpen) && !isReifiedStatement ? ( + handleSearchStringChange(ev.target.value)} + value={searchString || ""} + sx={(theme) => ({ + marginTop: theme.spacing(1), + marginBottom: theme.spacing(1), + })} + inputProps={{ + ref: inputRef, + onFocus: handleFocus, + onKeyUp: handleKeyUp, + }} + /> + ) : ( + + {!isReifiedStatement && ( + + + + + + + + + + + + + + + )} + + )} + {globalPath === formsPath && ( + + + + )} + + + ); +}; diff --git a/apps/exhibition-live/components/form/Docs.mdx b/packages/form-renderer/linked-data-renderer/src/Docs.mdx similarity index 91% rename from apps/exhibition-live/components/form/Docs.mdx rename to packages/form-renderer/linked-data-renderer/src/Docs.mdx index 5dd01dae..4d1b1080 100644 --- a/apps/exhibition-live/components/form/Docs.mdx +++ b/packages/form-renderer/linked-data-renderer/src/Docs.mdx @@ -1,6 +1,6 @@ import { Meta, Canvas } from "@storybook/blocks"; +import SemanticJSONFormNoOpsStories from "./SemanticJSONFormNoOps.stories"; -import * as SemanticJSONFormNoOpsStories from "./SemanticJSONFormNoOps.stories"; diff --git a/apps/exhibition-live/components/renderer/InlineCondensedSemanticFormsRenderer.tsx b/packages/form-renderer/linked-data-renderer/src/InlineCondensedSemanticFormsRenderer.tsx similarity index 83% rename from apps/exhibition-live/components/renderer/InlineCondensedSemanticFormsRenderer.tsx rename to packages/form-renderer/linked-data-renderer/src/InlineCondensedSemanticFormsRenderer.tsx index ba8f585b..24f1690e 100644 --- a/apps/exhibition-live/components/renderer/InlineCondensedSemanticFormsRenderer.tsx +++ b/packages/form-renderer/linked-data-renderer/src/InlineCondensedSemanticFormsRenderer.tsx @@ -17,25 +17,21 @@ import { import merge from "lodash/merge"; import React, { useCallback, useEffect, useMemo, useState } from "react"; -import DiscoverAutocompleteInput from "../form/discover/DiscoverAutocompleteInput"; -import { primaryFields, typeIRItoTypeName } from "../config"; -import { AutocompleteSuggestion } from "../form/DebouncedAutoComplete"; -import { extractFieldIfString } from "../utils/mapping/simpleFieldExtractor"; -import { PrimaryField } from "../utils/types"; +import { AutocompleteSuggestion } from "@slub/edb-core-types"; +import { extractFieldIfString } from "@slub/edb-data-mapping"; import { useGlobalSearchWithHelper, useRightDrawerState, useKeyEventForSimilarityFinder, -} from "../state"; -import { makeFormsPath } from "../utils/core"; -import { SearchbarWithFloatingButton } from "../layout/main-layout/Searchbar"; -import SimilarityFinder from "../form/SimilarityFinder"; + useAdbContext, +} from "@slub/edb-state-hooks"; +import { makeFormsPath } from "@slub/edb-ui-utils"; import { JSONSchema7 } from "json-schema"; -import { useRouter } from "next/router"; -import { useTranslation } from "next-i18next"; -import { EntityDetailListItem } from "../form/show"; +import { PrimaryField } from "@slub/edb-core-types"; +import { EntityDetailListItem } from "@slub/edb-advanced-components"; +import { SearchbarWithFloatingButton } from "@slub/edb-basic-components"; -const InlineCondensedSemanticFormsRenderer = (props: ControlProps) => { +const InlineCondensedSemanticFormsRendererComponent = (props: ControlProps) => { const { id, errors, @@ -49,11 +45,16 @@ const InlineCondensedSemanticFormsRenderer = (props: ControlProps) => { rootSchema, label, } = props; + const { + typeIRIToTypeName, + queryBuildOptions: { primaryFields }, + components: { SimilarityFinder }, + } = useAdbContext(); const appliedUiSchemaOptions = merge({}, config, uischema.options); const { $ref, typeIRI } = appliedUiSchemaOptions.context || {}; const typeName = useMemo( - () => typeIRI && typeIRItoTypeName(typeIRI), - [typeIRI], + () => typeIRI && typeIRIToTypeName(typeIRI), + [typeIRI, typeIRIToTypeName], ); const ctx = useJsonForms(); const [realLabel, setRealLabel] = useState(""); @@ -132,13 +133,10 @@ const InlineCondensedSemanticFormsRenderer = (props: ControlProps) => { [handleSelectedChange, closeDrawer], ); - const router = useRouter(); - const locale = router.query.locale || ""; - const searchOnDataPath = useMemo(() => { - const typeName = typeIRItoTypeName(typeIRI); + const typeName = typeIRIToTypeName(typeIRI); return primaryFields[typeName]?.label; - }, [typeIRI]); + }, [typeIRI, typeIRIToTypeName]); const labelKey = useMemo(() => { const fieldDecl = primaryFields[typeName] as PrimaryField | undefined; @@ -216,15 +214,10 @@ const InlineCondensedSemanticFormsRenderer = (props: ControlProps) => { {!hasValue ? ( - + handleSearchStringChange(ev.target.value)} value={searchString || ""} label={label} @@ -267,4 +260,6 @@ const InlineCondensedSemanticFormsRenderer = (props: ControlProps) => { ); }; -export default withJsonFormsControlProps(InlineCondensedSemanticFormsRenderer); +export const InlineCondensedSemanticFormsRenderer = withJsonFormsControlProps( + InlineCondensedSemanticFormsRendererComponent, +); diff --git a/apps/exhibition-live/components/renderer/InlineDropdownRenderer.tsx b/packages/form-renderer/linked-data-renderer/src/InlineDropdownRenderer.tsx similarity index 57% rename from apps/exhibition-live/components/renderer/InlineDropdownRenderer.tsx rename to packages/form-renderer/linked-data-renderer/src/InlineDropdownRenderer.tsx index 636cb469..46d5761a 100644 --- a/apps/exhibition-live/components/renderer/InlineDropdownRenderer.tsx +++ b/packages/form-renderer/linked-data-renderer/src/InlineDropdownRenderer.tsx @@ -1,25 +1,24 @@ -import { - ControlProps, - JsonSchema, - Resolve, - resolveSchema, -} from "@jsonforms/core"; +import { ControlProps, OwnPropsOfControl, Resolve } from "@jsonforms/core"; import { useJsonForms, withJsonFormsControlProps } from "@jsonforms/react"; import { FormControl, Hidden } from "@mui/material"; import merge from "lodash/merge"; import React, { useCallback, useEffect, useMemo, useState } from "react"; -import { primaryFields, typeIRItoTypeName } from "../config"; -import { AutocompleteSuggestion } from "../form/DebouncedAutoComplete"; -import { extractFieldIfString } from "../utils/mapping/simpleFieldExtractor"; -import { PrimaryField } from "../utils/types"; -import { makeFormsPath } from "../utils/core"; +import { AutocompleteSuggestion } from "@slub/edb-core-types"; +import { extractFieldIfString } from "@slub/edb-data-mapping"; +import { makeFormsPath } from "@slub/edb-ui-utils"; import { useTranslation } from "next-i18next"; -import { PreloadedOptionSelect } from "../form/PreloadedOptionSelect"; -import { findEntityByClass } from "../utils/discover"; -import { useGlobalCRUDOptions } from "../state/useGlobalCRUDOptions"; +import { + useAdbContext, + useDataStore, + useGlobalCRUDOptions, +} from "@slub/edb-state-hooks"; +import { PrimaryField } from "@slub/edb-core-types"; +import { PreloadedOptionSelect } from "@slub/edb-advanced-components"; +import { JSONSchema7 } from "json-schema"; +import get from "lodash/get"; -const InlineDropdownRenderer = (props: ControlProps) => { +const InlineDropdownRendererComponent = (props: ControlProps) => { const { id, schema, @@ -32,6 +31,13 @@ const InlineDropdownRenderer = (props: ControlProps) => { rootSchema, label, } = props; + const { + typeIRIToTypeName, + typeNameToTypeIRI, + queryBuildOptions, + jsonLDConfig: { defaultPrefix }, + } = useAdbContext(); + const { primaryFields } = queryBuildOptions; const appliedUiSchemaOptions = merge({}, config, uischema.options); const ctx = useJsonForms(); const [realLabel, setRealLabel] = useState(""); @@ -47,22 +53,6 @@ const InlineDropdownRenderer = (props: ControlProps) => { [data, realLabel], ); const { $ref, typeIRI } = appliedUiSchemaOptions.context || {}; - const subSchema = useMemo(() => { - if (!$ref) return; - const schema2 = { - ...schema, - $ref, - }; - const resolvedSchema = resolveSchema( - schema2 as JsonSchema, - "", - rootSchema as JsonSchema, - ); - return { - ...rootSchema, - ...resolvedSchema, - }; - }, [$ref, schema, rootSchema]); useEffect(() => { if (!data) setRealLabel(""); @@ -70,8 +60,12 @@ const InlineDropdownRenderer = (props: ControlProps) => { const handleSelectedChange = useCallback( (v: AutocompleteSuggestion) => { - if (!v) { - handleChange(path, undefined); + if (!v || v.value === null) { + let p = path; + if (path.endsWith("@id")) { + p = path.substring(0, path.length - ".@id".length); + } + handleChange(p, undefined); return; } if (v.value !== data) handleChange(path, v.value); @@ -108,8 +102,8 @@ const InlineDropdownRenderer = (props: ControlProps) => { }, [data, ctx?.core?.data, path, setRealLabel]); const typeName = useMemo( - () => typeIRI && typeIRItoTypeName(typeIRI), - [typeIRI], + () => typeIRI && typeIRIToTypeName(typeIRI), + [typeIRI, typeIRIToTypeName], ); const limit = useMemo(() => { @@ -119,24 +113,40 @@ const InlineDropdownRenderer = (props: ControlProps) => { const { t } = useTranslation(); const { crudOptions } = useGlobalCRUDOptions(); + + const { dataStore, ready } = useDataStore({ + schema: rootSchema as JSONSchema7, + crudOptionsPartial: crudOptions, + typeNameToTypeIRI, + queryBuildOptions, + }); const load = useCallback( async (searchString?: string) => - typeIRI && crudOptions - ? ( - await findEntityByClass( - searchString || null, - typeIRI, - crudOptions.selectFetch, + typeName && ready && dataStore + ? (async () => { + const documents = await dataStore.findDocuments( + typeName, + { + ...(searchString ? { search: searchString } : {}), + }, limit, - ) - ).map(({ name = "", value }: { name: string; value: any }) => { - return { - label: name, - value, - }; - }) + ); + + const results = []; + for (const item of documents) { + const primaryField = primaryFields[typeName]; + const primary = primaryField ? get(item, primaryField.label) : ""; + + results.push({ + label: primary, + value: item["@id"], + }); + } + + return results; + })() : [], - [typeIRI, crudOptions, limit], + [primaryFields, typeName, ready, dataStore, limit], ); return ( @@ -144,9 +154,8 @@ const InlineDropdownRenderer = (props: ControlProps) => { theme.spacing(1), + marginTop: (theme) => theme.spacing(2), marginBottom: (theme) => theme.spacing(1), }} > @@ -164,4 +173,8 @@ const InlineDropdownRenderer = (props: ControlProps) => { ); }; -export default withJsonFormsControlProps(InlineDropdownRenderer); +export const InlineDropdownRenderer: + | React.ComponentClass + | React.FunctionComponent = withJsonFormsControlProps( + InlineDropdownRendererComponent, +); diff --git a/apps/exhibition-live/components/renderer/InlineDropdownSemanticFormsRenderer.tsx b/packages/form-renderer/linked-data-renderer/src/InlineDropdownSemanticFormsRenderer.tsx similarity index 82% rename from apps/exhibition-live/components/renderer/InlineDropdownSemanticFormsRenderer.tsx rename to packages/form-renderer/linked-data-renderer/src/InlineDropdownSemanticFormsRenderer.tsx index 805c6a44..22b72007 100644 --- a/apps/exhibition-live/components/renderer/InlineDropdownSemanticFormsRenderer.tsx +++ b/packages/form-renderer/linked-data-renderer/src/InlineDropdownSemanticFormsRenderer.tsx @@ -10,32 +10,29 @@ import { FormControl, Hidden, List, - TextField, Theme, Typography, } from "@mui/material"; import merge from "lodash/merge"; import React, { useCallback, useEffect, useMemo, useState } from "react"; -import DiscoverAutocompleteInput from "../form/discover/DiscoverAutocompleteInput"; -import { primaryFields, typeIRItoTypeName } from "../config"; -import { AutocompleteSuggestion } from "../form/DebouncedAutoComplete"; -import { extractFieldIfString } from "../utils/mapping/simpleFieldExtractor"; -import { PrimaryField } from "../utils/types"; +import { AutocompleteSuggestion } from "@slub/edb-core-types"; +import { extractFieldIfString } from "@slub/edb-data-mapping"; import { + useAdbContext, useGlobalSearchWithHelper, useRightDrawerState, - useKeyEventForSimilarityFinder, -} from "../state"; -import { makeFormsPath } from "../utils/core"; -import { SearchbarWithFloatingButton } from "../layout/main-layout/Searchbar"; -import SimilarityFinder from "../form/SimilarityFinder"; +} from "@slub/edb-state-hooks"; +import { makeFormsPath } from "@slub/edb-ui-utils"; import { JSONSchema7 } from "json-schema"; -import { useRouter } from "next/router"; -import { useTranslation } from "next-i18next"; -import { EntityDetailListItem } from "../form/show"; +import { PrimaryField } from "@slub/edb-core-types"; +import { + DiscoverAutocompleteInput, + EntityDetailListItem, +} from "@slub/edb-advanced-components"; +import { SearchbarWithFloatingButton } from "@slub/edb-basic-components"; -const InlineDropdownSemanticFormsRenderer = (props: ControlProps) => { +const InlineDropdownSemanticFormsRendererComponent = (props: ControlProps) => { const { id, errors, @@ -49,11 +46,16 @@ const InlineDropdownSemanticFormsRenderer = (props: ControlProps) => { rootSchema, label, } = props; + const { + typeIRIToTypeName, + queryBuildOptions: { primaryFields }, + components: { SimilarityFinder }, + } = useAdbContext(); const appliedUiSchemaOptions = merge({}, config, uischema.options); const { $ref, typeIRI } = appliedUiSchemaOptions.context || {}; const typeName = useMemo( - () => typeIRI && typeIRItoTypeName(typeIRI), - [typeIRI], + () => typeIRI && typeIRIToTypeName(typeIRI), + [typeIRI, typeIRIToTypeName], ); const ctx = useJsonForms(); const [realLabel, setRealLabel] = useState(""); @@ -119,7 +121,7 @@ const InlineDropdownSemanticFormsRenderer = (props: ControlProps) => { } return label; }); - }, [data, ctx?.core?.data, path, setRealLabel]); + }, [data, ctx?.core?.data, path, setRealLabel, primaryFields]); const handleExistingEntityAccepted = useCallback( (entityIRI: string, data: any) => { @@ -132,13 +134,10 @@ const InlineDropdownSemanticFormsRenderer = (props: ControlProps) => { [handleSelectedChange, closeDrawer], ); - const router = useRouter(); - const locale = router.query.locale || ""; - const searchOnDataPath = useMemo(() => { - const typeName = typeIRItoTypeName(typeIRI); + const typeName = typeIRIToTypeName(typeIRI); return primaryFields[typeName]?.label; - }, [typeIRI]); + }, [typeIRI, typeIRIToTypeName]); const labelKey = useMemo(() => { const fieldDecl = primaryFields[typeName] as PrimaryField | undefined; @@ -180,8 +179,6 @@ const InlineDropdownSemanticFormsRenderer = (props: ControlProps) => { [handleMappedData, closeDrawer], ); - const { t } = useTranslation(); - const showAsFocused = useMemo( () => isActive && sidebarOpen, [isActive, sidebarOpen], @@ -222,11 +219,7 @@ const InlineDropdownSemanticFormsRenderer = (props: ControlProps) => { {!hasValue ? ( - + { ); }; -export default withJsonFormsControlProps(InlineDropdownSemanticFormsRenderer); +export const InlineDropdownSemanticFormsRenderer = withJsonFormsControlProps( + InlineDropdownSemanticFormsRendererComponent, +); diff --git a/apps/exhibition-live/components/renderer/MaterialArrayChipsLayout.tsx b/packages/form-renderer/linked-data-renderer/src/MaterialArrayChipsLayout.tsx similarity index 77% rename from apps/exhibition-live/components/renderer/MaterialArrayChipsLayout.tsx rename to packages/form-renderer/linked-data-renderer/src/MaterialArrayChipsLayout.tsx index c090cc39..1d21cece 100644 --- a/apps/exhibition-live/components/renderer/MaterialArrayChipsLayout.tsx +++ b/packages/form-renderer/linked-data-renderer/src/MaterialArrayChipsLayout.tsx @@ -12,19 +12,15 @@ import React, { useCallback, useEffect, useMemo, useState } from "react"; import { ArrayLayoutToolbar } from "./ArrayToolbar"; import { useJsonForms } from "@jsonforms/react"; -import { memo } from "./config"; import { uniqBy, orderBy } from "lodash"; import { SemanticFormsModal } from "./SemanticFormsModal"; -import { BASE_IRI } from "../config"; -import { irisToData, makeFormsPath } from "../utils/core"; +import { irisToData, makeFormsPath } from "@slub/edb-ui-utils"; import { JSONSchema7 } from "json-schema"; -import { defaultJsonldContext, slent } from "../form/formConfigs"; -import { v4 as uuidv4 } from "uuid"; -import { Box, Grid, IconButton, List, Stack } from "@mui/material"; +import { Box, Grid, IconButton, Stack } from "@mui/material"; import { SemanticFormsInline } from "./SemanticFormsInline"; import AddIcon from "@mui/icons-material/Add"; -import { useGlobalCRUDOptions } from "../state/useGlobalCRUDOptions"; -import { useCRUDWithQueryClient } from "../state/useCRUDWithQueryClient"; +import { useAdbContext } from "@slub/edb-state-hooks"; +import { useCRUDWithQueryClient } from "@slub/edb-state-hooks"; import { useSnackbar } from "notistack"; import { SimpleChipRenderer } from "./SimpleChipRenderer"; import { bringDefinitionToTop } from "@slub/json-schema-utils"; @@ -34,9 +30,10 @@ type OwnProps = { }; const MaterialArrayChipsLayoutComponent = (props: ArrayLayoutProps & {}) => { const innerCreateDefaultValue = useCallback( - () => createDefaultValue(props.schema), - [props.schema], + () => createDefaultValue(props.schema, props.rootSchema), + [props.schema, props.rootSchema], ); + const { createEntityIRI, typeIRIToTypeName } = useAdbContext(); const { data, path, @@ -49,36 +46,45 @@ const MaterialArrayChipsLayoutComponent = (props: ArrayLayoutProps & {}) => { config, removeItems, } = props; - const appliedUiSchemaOptions = merge({}, config, props.uischema.options); + const { + isReifiedStatement, + hideRequiredAsterisk, + additionalKnowledgeSources, + elementLabelTemplate, + elementLabelProp = "label", + } = useMemo( + () => merge({}, config, props.uischema.options), + [config, props.uischema.options], + ); const { readonly, core } = useJsonForms(); const realData = Resolve.data(core.data, path); const typeIRI = schema.properties?.["@type"]?.const; const [modalIsOpen, setModalIsOpen] = useState(false); + const typeName = useMemo( + () => typeIRIToTypeName(typeIRI), + [typeIRI, typeIRIToTypeName], + ); + const [formData, setFormData] = useState( - irisToData(slent(uuidv4()).value, typeIRI), + irisToData(createEntityIRI(typeName), typeIRI), ); const handleCreateNew = useCallback(() => { - setFormData(irisToData(slent(uuidv4()).value, typeIRI)); + setFormData(irisToData(createEntityIRI(typeName), typeIRI)); setModalIsOpen(true); - }, [setModalIsOpen, setFormData, typeIRI]); - const typeName = useMemo( - () => typeIRI && typeIRI.substring(BASE_IRI.length, typeIRI.length), - [typeIRI], - ); + }, [setModalIsOpen, setFormData, typeIRI, typeName]); const subSchema = useMemo( () => bringDefinitionToTop(rootSchema as JSONSchema7, typeName) as JsonSchema, [rootSchema, typeName], ); - const { crudOptions } = useGlobalCRUDOptions(); const entityIRI = useMemo(() => formData["@id"], [formData]); - const { saveMutation } = useCRUDWithQueryClient( + const { saveMutation } = useCRUDWithQueryClient({ entityIRI, typeIRI, - subSchema as JSONSchema7, - { enabled: false }, - ); + schema: subSchema as JSONSchema7, + queryOptions: { enabled: false }, + }); const { enqueueSnackbar } = useSnackbar(); const handleSaveAndAdd = useCallback(() => { @@ -91,9 +97,8 @@ const MaterialArrayChipsLayoutComponent = (props: ArrayLayoutProps & {}) => { .then((res) => { enqueueSnackbar("Saved", { variant: "success" }); addItem(path, res)(); - const id = slent(uuidv4()).value; setFormData({ - "@id": id, + "@id": createEntityIRI(typeName), "@type": typeIRI, }); }) @@ -102,7 +107,7 @@ const MaterialArrayChipsLayoutComponent = (props: ArrayLayoutProps & {}) => { variant: "error", }); }); - }, [saveMutation, typeIRI, addItem, setFormData]); + }, [saveMutation, typeIRI, typeName, addItem, setFormData]); const handleAddNew = useCallback(() => { setModalIsOpen(false); @@ -111,16 +116,14 @@ const MaterialArrayChipsLayoutComponent = (props: ArrayLayoutProps & {}) => { setFormData({}); }, [setModalIsOpen, addItem, formData, setFormData, typeIRI]); - const isReifiedStatement = Boolean(appliedUiSchemaOptions.isReifiedStatement); - const formsPath = useMemo( () => makeFormsPath(config?.formsPath, path), [config?.formsPath, path], ); useEffect(() => { - setFormData(irisToData(slent(uuidv4()).value, typeIRI)); - }, [formsPath, typeIRI, setFormData]); + setFormData(irisToData(createEntityIRI(typeName), typeIRI)); + }, [formsPath, typeIRI, typeName, setFormData]); return ( { label={computeLabel( label, Boolean(required), - appliedUiSchemaOptions.hideRequiredAsterisk, + Boolean(hideRequiredAsterisk), )} errors={errors} path={path} @@ -141,8 +144,9 @@ const MaterialArrayChipsLayoutComponent = (props: ArrayLayoutProps & {}) => { onCreate={handleCreateNew} createDefault={innerCreateDefaultValue} readonly={readonly} - isReifiedStatement={isReifiedStatement} + isReifiedStatement={Boolean(isReifiedStatement)} formsPath={makeFormsPath(config?.formsPath, path)} + additionalKnowledgeSources={additionalKnowledgeSources} /> {modalIsOpen && ( { index={index} count={count} path={childPath} - childLabelTemplate={ - appliedUiSchemaOptions.elementLabelTemplate - } - elementLabelProp={ - appliedUiSchemaOptions.elementLabelProp || "label" - } + childLabelTemplate={elementLabelTemplate} + elementLabelProp={elementLabelProp} formsPath={makeFormsPath(config?.formsPath, childPath)} sx={{ margin: 0.5, @@ -234,4 +234,4 @@ const MaterialArrayChipsLayoutComponent = (props: ArrayLayoutProps & {}) => { ); }; -export const MaterialArrayChipsLayout = memo(MaterialArrayChipsLayoutComponent); +export const MaterialArrayChipsLayout = MaterialArrayChipsLayoutComponent; diff --git a/packages/form-renderer/linked-data-renderer/src/MaterialArrayLayout.tsx b/packages/form-renderer/linked-data-renderer/src/MaterialArrayLayout.tsx new file mode 100644 index 00000000..2410985d --- /dev/null +++ b/packages/form-renderer/linked-data-renderer/src/MaterialArrayLayout.tsx @@ -0,0 +1,394 @@ +import { + ArrayLayoutProps, + composePaths, + computeLabel, + createDefaultValue, + JsonSchema, + JsonSchema7, + Resolve, +} from "@jsonforms/core"; +import merge from "lodash/merge"; +import React, { + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from "react"; + +import { ArrayLayoutToolbar } from "./ArrayToolbar"; +import { useJsonForms } from "@jsonforms/react"; +import { uniqBy, orderBy } from "lodash"; +import { SimpleExpandPanelRenderer } from "./SimpleExpandPanelRenderer"; +import { SemanticFormsModal } from "./SemanticFormsModal"; +import { irisToData, makeFormsPath, validate } from "@slub/edb-ui-utils"; +import { JSONSchema7 } from "json-schema"; +import { Box, Grid, IconButton, List, Paper, Tooltip } from "@mui/material"; +import { SemanticFormsInline } from "./SemanticFormsInline"; +import CheckIcon from "@mui/icons-material/Check"; +import { + useAdbContext, + useCRUDWithQueryClient, + useFormDataStore, +} from "@slub/edb-state-hooks"; +import { useSnackbar } from "notistack"; +import { ErrorObject } from "ajv"; +import { applyToEachField, extractFieldIfString } from "@slub/edb-data-mapping"; +import { JSONSchema } from "json-schema-to-ts"; +import { useTranslation } from "next-i18next"; +import { bringDefinitionToTop } from "@slub/json-schema-utils"; +import { Pulse } from "@slub/edb-basic-components"; + +const uiSchemaOptionsSchema = { + type: "object", + properties: { + labelAsHeadline: { + type: "boolean", + }, + hideRequiredAsterisk: { + type: "boolean", + }, + isReifiedStatement: { + type: "boolean", + }, + orderBy: { + type: "string", + }, + autoFocusOnValid: { + type: "boolean", + }, + additionalKnowledgeSources: { + type: "array", + items: { + type: "string", + }, + }, + elementDetailItemPath: { + type: "string", + }, + elementLabelTemplate: { + type: "string", + }, + elementLabelProp: { + type: "string", + }, + imagePath: { + type: "string", + }, + }, +} as const satisfies JSONSchema; + +export const MaterialArrayLayout = (props: ArrayLayoutProps) => { + const innerCreateDefaultValue = useCallback( + () => createDefaultValue(props.schema, props.rootSchema), + [props.schema, props.rootSchema], + ); + const { + data, + path, + schema, + errors, + addItem, + label, + required, + rootSchema, + config, + removeItems, + uischema, + enabled, + } = props; + const { readonly, core } = useJsonForms(); + const realData = Resolve.data(core.data, path); + const { + createEntityIRI, + typeIRIToTypeName, + typeNameToTypeIRI, + queryBuildOptions: { primaryFields, primaryFieldExtracts }, + } = useAdbContext(); + const typeIRI = useMemo(() => { + const lastScopeSegement = path.split("/").pop(); + let iri = schema.properties?.["@type"]?.const; + try { + if (!iri) { + const type = + rootSchema.properties?.[lastScopeSegement]?.items?.["$ref"]; + const lastSegment = type?.split("/").pop(); + iri = lastSegment ? typeNameToTypeIRI(lastSegment) : ""; + } + } catch (e) { + console.error(e); + } + return iri; + }, [schema, rootSchema, path, typeNameToTypeIRI]); + const typeName = useMemo( + () => typeIRIToTypeName(typeIRI), + [typeIRI, typeIRIToTypeName], + ); + const [modalIsOpen, setModalIsOpen] = useState(false); + + const { t } = useTranslation(); + + const [entityIRI, setEntityIRI] = useState(createEntityIRI(typeName)); + const { formData, setFormData } = useFormDataStore({ + entityIRI, + typeIRI, + createNewEntityIRI: () => createEntityIRI(typeName), + autoCreateNewEntityIRI: true, + }); + + const addButtonRef = useRef(null); + + const handleInlineFormDataChange = useCallback( + (data: any) => { + setFormData(data); + }, + [setFormData], + ); + + const handleCreateNew = useCallback(() => { + setFormData(irisToData(createEntityIRI(typeName), typeIRI)); + setModalIsOpen(true); + }, [setModalIsOpen, setFormData, typeIRI, typeName]); + const subSchema = useMemo( + () => + bringDefinitionToTop(rootSchema as JSONSchema7, typeName) as JsonSchema, + [rootSchema, typeName], + ); + const { saveMutation } = useCRUDWithQueryClient({ + entityIRI, + typeIRI, + schema: subSchema as JSONSchema7, + queryOptions: { enabled: false }, + }); + + const { enqueueSnackbar } = useSnackbar(); + const handleSaveAndAdd = useCallback(() => { + const finalData = { + ...formData, + }; + saveMutation + .mutateAsync(finalData) + .then((res) => { + enqueueSnackbar(t("successfully saved"), { variant: "success" }); + addItem(path, res)(); + setEntityIRI(createEntityIRI(typeName)); + }) + .catch((e) => { + enqueueSnackbar(t("error while saving") + e.message, { + variant: "error", + }); + }); + }, [saveMutation, typeIRI, typeName, createEntityIRI, addItem, setFormData]); + + const handleAddNew = useCallback(() => { + setModalIsOpen(false); + //if(typeof saveMethod === 'function') saveMethod(); + addItem(path, formData)(); + setFormData({}); + }, [setModalIsOpen, addItem, formData, setFormData, typeIRI]); + + const { + isReifiedStatement, + orderBy: orderByPropertyPath, + autoFocusOnValid, + additionalKnowledgeSources, + elementDetailItemPath, + elementLabelTemplate, + elementLabelProp = "label", + imagePath, + labelAsHeadline, + hideRequiredAsterisk, + } = useMemo(() => { + const appliedUiSchemaOptions = merge({}, config, uischema.options); + if (validate(uiSchemaOptionsSchema, appliedUiSchemaOptions)) { + return appliedUiSchemaOptions; + } + return {}; + }, [config, uischema.options]); + + const [inlineErrors, setInlineErrors] = useState(null); + const handleErrors = useCallback( + (err: ErrorObject[]) => { + setInlineErrors(err); + }, + [setInlineErrors], + ); + + useEffect(() => { + if ( + inlineErrors?.length === 0 && + addButtonRef.current && + autoFocusOnValid + ) { + addButtonRef.current.focus(); + } + }, [inlineErrors, autoFocusOnValid]); + + const formsPath = useMemo( + () => makeFormsPath(config?.formsPath, path), + [config?.formsPath, path], + ); + + useEffect(() => { + setFormData(irisToData(createEntityIRI(typeName), typeIRI)); + }, [formsPath, typeIRI, createEntityIRI, typeName, setFormData]); + + const orderedAndUniqueData = useMemo(() => { + return orderBy( + uniqBy( + realData?.map((childData, index) => { + const fieldDecl = primaryFieldExtracts[typeName]; + if (childData && fieldDecl) { + let label = + childData.label || childData.__label || childData["@id"]; + const extractedInfo = applyToEachField( + childData, + fieldDecl, + extractFieldIfString, + ); + if (extractedInfo.label) { + label = extractedInfo.label; + } + } + return { + id: childData?.["@id"], + childData, + index, + label, + }; + }), + "id", + ), + ["label", "asc"], + ); + }, [realData, orderByPropertyPath, primaryFieldExtracts, typeIRI, typeName]); + + const [tooltipEnabled, setTooltipEnabled] = useState(false); + + return ( +
+ + {modalIsOpen && ( + setModalIsOpen(false)} + onChange={(entityIRI) => + entityIRI && setFormData({ "@id": entityIRI }) + } + onFormDataChange={(data) => setFormData(data)} + formsPath={makeFormsPath(config?.formsPath, path)} + /> + )} + {isReifiedStatement && ( + + + + + + + +
{t("some error")}
+
+ {inlineErrors.map((e, i) => ( +
{e.message}
+ ))} +
+ + ) + } + onClose={() => setTooltipEnabled(false)} + open={tooltipEnabled && inlineErrors?.length > 0} + > + setTooltipEnabled(true)}> + 0} + onClick={handleSaveAndAdd} + ref={addButtonRef} + > + + + + + +
+
+
+
+ )} + + {data > 0 + ? orderedAndUniqueData.map( + ({ id: expandID, childData, index }: any, count) => { + const childPath = composePaths(path, `${index}`); + return ( + {}} + rootSchema={rootSchema} + entityIRI={expandID} + typeIRI={typeIRI} + typeName={typeName} + data={childData} + key={expandID} + index={index} + count={count} + path={childPath} + imagePath={imagePath} + elementDetailItemPath={elementDetailItemPath} + childLabelTemplate={elementLabelTemplate} + elementLabelProp={elementLabelProp} + formsPath={formsPath} + primaryFields={primaryFields} + /> + ); + }, + ) + : null} + +
+ ); +}; diff --git a/apps/exhibition-live/components/renderer/MaterialArrayOfLinkedItemChipsRenderer.tsx b/packages/form-renderer/linked-data-renderer/src/MaterialArrayOfLinkedItemChipsRenderer.tsx similarity index 66% rename from apps/exhibition-live/components/renderer/MaterialArrayOfLinkedItemChipsRenderer.tsx rename to packages/form-renderer/linked-data-renderer/src/MaterialArrayOfLinkedItemChipsRenderer.tsx index add3f3c5..4914fe08 100644 --- a/apps/exhibition-live/components/renderer/MaterialArrayOfLinkedItemChipsRenderer.tsx +++ b/packages/form-renderer/linked-data-renderer/src/MaterialArrayOfLinkedItemChipsRenderer.tsx @@ -1,19 +1,11 @@ -import { - and, - ArrayLayoutProps, - isObjectArray, - optionIs, - RankedTester, - rankWith, -} from "@jsonforms/core"; +import { ArrayLayoutProps } from "@jsonforms/core"; import { withJsonFormsArrayLayoutProps } from "@jsonforms/react"; import { Hidden } from "@mui/material"; import React, { useCallback } from "react"; -import { MaterialArrayLayout } from "./MaterialArrayLayout"; import { MaterialArrayChipsLayout } from "./MaterialArrayChipsLayout"; -export const MaterialArrayOfLinkedItemChipsRenderer = ({ +const MaterialArrayOfLinkedItemChipsRendererComponent = ({ visible, enabled, id, @@ -29,7 +21,6 @@ export const MaterialArrayOfLinkedItemChipsRenderer = ({ uischemas, addItem, removeItems, - translations, }: ArrayLayoutProps) => { const addItemCb = useCallback( (p: string, value: any) => addItem(p, value), @@ -38,7 +29,6 @@ export const MaterialArrayOfLinkedItemChipsRenderer = ({ return (