{"_id":"@adishare/strapi-plugin-import-export-entries","name":"@adishare/strapi-plugin-import-export-entries","dist-tags":{"latest":"1.23.2"},"versions":{"1.23.2":{"name":"@adishare/strapi-plugin-import-export-entries","version":"1.23.2","description":"Import/Export data from and to your database in just few clicks.","strapi":{"name":"import-export-entries","description":"Import/Export data from and to your database in just few clicks.","kind":"plugin","displayName":"Import Export Entries"},"scripts":{"build":"tsc --build","build:clean":"rm -rf libs server types","dev":"nodemon --exec yarn build","lint:check":"eslint ./src ./admin && yarn prettier --check ./src ./admin","lint:fix":"eslint ./src ./admin --fix && yarn prettier --write ./src ./admin","test":"jest --forceExit --detectOpenHandles --runInBand","test:watch":"jest --forceExit --detectOpenHandles --runInBand --watch","prepublishOnly":"yarn build:clean && yarn build","release":"standard-version","release:patch":"standard-version --release-as patch","release:minor":"standard-version --release-as minor","release:major":"standard-version --release-as major"},"dependencies":{"@monaco-editor/react":"4.4.5","csvtojson":"2.0.10","deepmerge":"^4.2.2","joi":"17.6.0","lodash":"4.17.21","monaco-editor":"0.33.0","monaco-editor-webpack-plugin":"7.0.1","node-fetch":"2.6.9","react-singleton-hook":"3.3.0"},"devDependencies":{"@babel/core":"^7.18.5","@babel/eslint-parser":"^7.18.2","@babel/preset-react":"^7.17.12","@faker-js/faker":"^7.5.0","@strapi/plugin-i18n":"^4.10.5","@strapi/plugin-seo":"^1.8.0","@strapi/plugin-users-permissions":"^4.10.5","@strapi/strapi":"^4.10.5","@types/fs-extra":"^11.0.1","@types/jest":"^29.5.8","@types/node-fetch":"^2.6.3","better-sqlite3":"^9.1.1","eslint":"^8.23.0","eslint-plugin-jest":"^27.0.1","eslint-plugin-react":"^7.30.1","eslint-plugin-simple-import-sort":"^8.0.0","jest":"^29.0.2","nodemon":"^2.0.22","prettier":"^2.7.1","standard-version":"^9.5.0","supertest":"^6.2.4","ts-jest":"^29.1.1","typescript":"^5.0.3"},"peerDependencies":{"@strapi/strapi":"^4.10.5"},"author":{"name":"Adishare","url":"https://github.com/adishare"},"maintainers":[{"name":"adishare","email":"adie.share@gmail.com"}],"engines":{"node":">=14.19.1 <=20.x.x","npm":">=6.0.0"},"keywords":["strapi","plugin","strapi","import","data","export","data","content"],"repository":{"type":"git","url":"git+https://github.com/adishare/strapi-plugin-import-export-entries.git"},"bugs":{"url":"https://github.com/adishare/strapi-plugin-import-export-entries/issues"},"homepage":"https://github.com/adishare/strapi-plugin-import-export-entries#readme","license":"MIT","gitHead":"5e9708b28043ae9615d665e78d0e8d3ee3fdd640","_id":"@adishare/strapi-plugin-import-export-entries@1.23.2","_nodeVersion":"18.17.1","_npmVersion":"9.6.7","dist":{"integrity":"sha512-2B5rDaUGxZDiH+UqsEmuVu1y2eYwDoaiUbtDPEZVpC311eBKrqZ5V482HUa/fiKRWtG8SwNuUEOKsyXh0BU44w==","shasum":"d8665d12338e93878f957c6efd111e58314f339e","tarball":"https://registry.npmjs.org/@adishare/strapi-plugin-import-export-entries/-/strapi-plugin-import-export-entries-1.23.2.tgz","fileCount":112,"unpackedSize":3264371,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDIUSaf6eo3MioHmXzC62yMHSp/pRqjmK05UmKG4at3EQIgH6Rm51GE/xoQqyfPbdgvrfxWMTD+pVbLVqOJinjOFC8="}]},"_npmUser":{"name":"adishare","email":"adie.share@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/strapi-plugin-import-export-entries_1.23.2_1718415074910_0.1441709106331015"},"_hasShrinkwrap":false}},"time":{"created":"2024-06-15T01:31:14.702Z","1.23.2":"2024-06-15T01:31:15.076Z","modified":"2024-06-15T01:31:15.418Z"},"maintainers":[{"name":"adishare","email":"adie.share@gmail.com"}],"description":"Import/Export data from and to your database in just few clicks.","homepage":"https://github.com/adishare/strapi-plugin-import-export-entries#readme","keywords":["strapi","plugin","strapi","import","data","export","data","content"],"repository":{"type":"git","url":"git+https://github.com/adishare/strapi-plugin-import-export-entries.git"},"author":{"name":"Adishare","url":"https://github.com/adishare"},"bugs":{"url":"https://github.com/adishare/strapi-plugin-import-export-entries/issues"},"license":"MIT","readme":"# Strapi Plugin Import Export Entries\n\nImport/Export data from and to your database in just few clicks.\n\n<p align=\"center\">\n  <img src=\"./doc/logo.png\" alt=\"UI\" width=\"300\"/>\n</p>\n\n## Features\n\n### Import\n\n- Import data directly from the Content Manager\n- Import data from JSON file or from typing raw text according to user permissions\n- Import contents to collection type/single type (components, dynamic zones and media are supported)\n- Control which roles can import data from the admin UI.\n\n### Export\n\n- Export data directly from the Content Manager\n- Export JSON contents according to user permissions\n- Download files or copy exported data to clipboard\n- Filter & sort data using Content Manager filters & sorting\n- Export plugins content types\n- Control which roles can export data from the admin UI.\n\n### Known Limitations\n\nAt the moment, dynamic zones and media are not unit tested. Tests will be implemented in a near future to improve quality and development speed.\n\n## Screenshots\n\n<p align=\"center\">\n  <img src=\"./doc/scr-ui.png\" alt=\"UI\" width=\"500\"/>\n</p>\n<p align=\"center\">\n  <img src=\"./doc/scr-ui-import.png\" alt=\"UI\" width=\"500\"/>\n</p>\n<p align=\"center\">\n  <img src=\"./doc/scr-ui-export.png\" alt=\"UI\" width=\"500\"/>\n</p>\n\n## Table Of Content\n\n- [Requirements](#requirements)\n- [Feedback](#feedback)\n- [Contribute](#contribute)\n- [Installation](#installation)\n- [Rebuild The Admin Panel](#rebuild-the-admin-panel)\n- [Usage](#usage)\n  - [Access Control](#access-control)\n  - [Preferences](#preferences)\n  - [Config](#config)\n    - [Available Options](#available-options)\n    - [`idField` Per Collection](#idfield-per-collection)\n    - [Importing Large Files](#importing-large-files)\n  - [Filtering & Sorting](#filtering-and-sorting)\n  - [Services](#services)\n  - [Content API](#content-api)\n  - [Webhook](#webhook)\n- [Importing Data](#importing-data)\n  - [JSON v2](#json-v2)\n  - [JSON v1 (deprecated)](#json-v1-deprecated)\n- [Related Plugins](#related-plugins)\n- [Author](#author)\n- [Acknowledgments](#acknowledgments)\n\n## Requirements\n\nStrapi v4 is required.\n\n## Feedback\n\n<p align=\"center\">\n  <img src=\"./doc/map.png\" alt=\"Product roadmap\" width=\"100\"/>\n</p>\n\nAccess the [publicly available product roadmap](https://strapi-import-export-entries.canny.io) and suggest features, report bugs or upvote other people suggestions.\n\n<p align=\"center\">\n  <img src=\"./doc/discord-logo.png\" alt=\"Discord community\" width=\"100\"/>\n</p>\n\nJoin the [Discord Community](https://discord.gg/dcqCAFFdP8) to give your feedback 📣 and get some help from the community ⛑️\n\n## Contribute\n\nSee the repo [Strapi Contribute](https://github.com/Baboo7/strapi-contribute#readme).\n\n## Installation\n\n1. Download\n\n```\nyarn add strapi-plugin-import-export-entries\n```\n\nor\n\n```\nnpm i strapi-plugin-import-export-entries\n```\n\n2. Enable the plugin\n\nAdd in the file `config/plugins.js`:\n\n```js\nmodule.exports = ({ env }) => ({\n  //...\n  'import-export-entries': {\n    enabled: true,\n    config: {\n      // See `Config` section.\n    },\n  },\n  //...\n});\n```\n\n## Rebuild The Admin Panel\n\nNew releases can introduce changes to the administration panel that require a rebuild. Rebuild the admin panel with one of the following commands:\n\n```\nyarn build --clean\n```\n\nor\n\n```\nnpm run build --clean\n```\n\n# Usage\n\nOnce the plugin is installed and setup, the functionnalities for a collection are accessible on its content management page.\n\n<p align=\"center\">\n  <img src=\"./doc/scr-usage.png\" alt=\"UI\" width=\"500\"/>\n</p>\n\nYou can also export the whole database from the home page of the plugin.\n\n<p align=\"center\">\n  <img src=\"./doc/scr-homepage.png\" alt=\"UI\" width=\"500\"/>\n</p>\n\n## Access Control\n\nYou can define which roles can import and/or export data from the admin UI.\n\nGo to `Settings > Roles (under Administration Panel) > Plugins > Import-export-entries`.\n\n<p align=\"center\">\n  <img src=\"./doc/access-control-admin.png\" alt=\"UI\" width=\"500\"/>\n</p>\n<p align=\"center\">\n  <em>Admin view.</em>\n</p>\n\n<br>\n\n<p align=\"center\">\n  <img src=\"./doc/access-control-user-homepage.png\" alt=\"UI\" width=\"500\"/>\n</p>\n<p align=\"center\">\n  <em>User view of the plugin home page that can only export data.</em>\n</p>\n\n<br>\n\n<p align=\"center\">\n  <img src=\"./doc/access-control-user-content-manager.png\" alt=\"UI\" width=\"500\"/>\n</p>\n<p align=\"center\">\n  <em>User view of the content management page that can only export data.</em>\n</p>\n\n## Preferences\n\nFor a quick and convenient use, you can set your preferences from the home page of the plugin.\n\n<p align=\"center\">\n  <img src=\"./doc/scr-homepage-preferences.png\" alt=\"UI\" width=\"500\"/>\n</p>\n\nOnce set, they will be used each time you import/export data.\n\n## Config\n\n### Available Options\n\nIn `config/plugins.js`:\n\n```ts\nmodule.exports = ({ env }) => ({\n  //...\n  'import-export-entries': {\n    enabled: true,\n    config: {\n      /**\n       * Public hostname of the server.\n       *\n       * If you use the local provider to persist medias,\n       * `serverPublicHostname` should be set to properly export media urls.\n       */\n      serverPublicHostname: 'https://yoga.com', // default: \"\".\n    },\n  },\n  //...\n});\n```\n\nIn any collection schema `schema.json`:\n\n```ts\n{\n  \"collectionName\": \"my-awesome-collection\",\n  \"info\": {\n    \"displayName\": \"My Awesome Collection\",\n  },\n  \"pluginOptions\": {\n    \"import-export-entries\": {\n      /**\n       * Define the `idField` used to find an entry of the collection\n       * when importing data.\n       *\n       * `idField` must match the name of an attribute.\n       * See section _Specifying `idField` Per Collection_ for more details\n       */\n      \"idField\": \"name\"\n    }\n  },\n  \"attributes\": {\n    /**\n     * In this example, `name` will be used to find an entry\n     * of this collection when importing data.\n     */\n    \"name\": {\n      \"type\": \"string\",\n      \"unique\": true\n    },\n  }\n}\n```\n\n<a id='idfield-per-collection'></a>\n\n### Specifying `idField` Per Collection\n\nImporting data will either create entries if they don't exist, or update them otherwise.\n\nWhen transfering data from a database to another, relying on the `id` of an entry is not reliable. For example, if you are transfering data on hospitals with this schema:\n\n```ts\ninterface Hospital {\n  id: number;\n  name: string;\n  employees: Employee[];\n  patients: Patient[];\n}\n```\n\nYou will have something similar in your source and target databases:\n\n```ts\n// data in source database\n{\n  id: 1,\n  name: \"Pitié Salpêtrière\",\n  employees: [2, 3],\n  patients: [4, 5],\n}\n\n// data in target database\n{\n  id: 11,\n  name: \"Pitié Salpêtrière\",\n  employees: [12, 13],\n  patients: [14, 15],\n}\n```\n\n_Different databases, different `id`s._ 🫠\n\nThat's why we need a way to define the field used to find an entry in a collection. This field is called an `idField`.\n\nTo define the `idField` of a collection, add it in the `pluginOptions` of the collection, under the property `import-export-entries`. Using the example above, this is how we would define the `idField` of the collection `hospital`:\n\n```ts\n{\n  \"collectionName\": \"hospitals\",\n  \"info\": {\n    \"displayName\": \"Hospital\",\n  },\n  \"options\": {},\n  /**\n   * In the property `pluginOptions`, define the `idField` under the property `import-export-entries`.\n   *\n   * `idField` must match the name of an attribute.\n   */\n  \"pluginOptions\": {\n    \"import-export-entries\": {\n      \"idField\": \"name\"\n    }\n  },\n  \"attributes\": {\n    \"name\": { // 👈 `name` will be used to find a hospital when importing data.\n      \"type\": \"string\",\n      \"unique\": true\n    },\n    \"employees\": {\n      \"type\": \"relation\",\n      \"relation\": \"oneToMany\",\n      \"target\": \"api::employees.employees\"\n    },\n    \"patients\": {\n      \"type\": \"relation\",\n      \"relation\": \"oneToMany\",\n      \"target\": \"api::patients.patients\"\n    },\n  }\n}\n```\n\nFor each collection of your application, you can define a different `idField`. For example, you can set the `name` attribute as the `idField` of the collection `hospital`, and for the collection `patients` use the attribute `ssn` (I really hope you're not storing uncyphered SSNs in your database 😬).\n\n> How does the search behave if I don't define explicitly the `idField` of a collection?\n\nBy default, the `idField` of a collection is the `id` attribute. We can imagine in a near future to automatically detect unique scalar fields of a collection and use them by default, but it's not the case at the moment.\n\n> How does the search behave when I specify the `idField` from the strapi admin UI?\n\nThe `idField` specified from the import modal of the admin UI takes precedence over the one defined in the `pluginOptions` of the collection.\n\nThis default behavior could change in the future if user feedback shows it's cumbersome to set it manually on each import. You tell me.\n\n### Importing Large Files\n\nWhen importing data, imported file size may exceed the file size limit of the server. To lift up the limit, configure the [Strapi middleware `body`](https://docs.strapi.io/developer-docs/latest/setup-deployment-guides/configurations/required/middlewares.html#body):\n\n```js\n// ./config/middlewares.js\n\nmodule.exports = {\n  // ...\n  {\n    name: 'strapi::body',\n    config: {\n      jsonLimit: '10mb',\n    },\n  },\n  // ...\n}\n```\n\n## Filtering and Sorting\n\nThe filtering and sorting mechanism relies on Strapi filtering and sorting feature:\n\n1. Connect to the content manager page of the model you want to export, and filter and sort the data as you want it to be exported.\n\n<p align=\"center\">\n  <img src=\"./doc/scr-add-filter-and-sort.png\" alt=\"UI\" width=\"500\"/>\n</p>\n\n2. Open the export modal and check the option _Apply filters and sort to exported data_.\n\n<p align=\"center\">\n  <img src=\"./doc/scr-check-apply-filters-sort-option.png\" alt=\"UI\" width=\"500\"/>\n</p>\n\n3. Click on _Fetch Data_.\n\nThe exported data is filtered and sorted as expected.\n\n## Services\n\n```ts\n/*****************************\n * Service \"import\".\n ****************************/\n\n/**\n * Get the service.\n */\nconst service = strapi.plugin(\"import-export-entries\").service(\"import\");\n\n/**\n * Method importData.\n */\nawait service.importData(\n  /**\n   * Data to import.\n   * Expected type depends on the specified format:\n   * - csv: string\n   * - jso: object | object[]\n   * - json: string\n   */\n  dataRaw: object | object[] | string,\n  options: {\n    /**\n     * Slug of the imported model.\n     * - \"media\" is a custom slug to specifically import media. See section Importing Data > Media below.\n     */\n    slug: \"media\" | string;\n    /**\n     * Format of the imported data.\n     * - csv\n     * - jso: javascript object\n     * - json: javascript object notation\n     */\n    format: \"csv\" | \"jso\" | \"json\";\n    /** User importing data. */\n    user: object;\n  }\n) : Promise<{\n  failures: {\n    /** Error raised. */\n    error: Error;\n    /** Data for which import failed. */\n    data: object;\n  }[]\n}>;\n```\n\n```ts\n/*****************************\n * Service \"export\".\n ****************************/\n\n/**\n * Get the service.\n */\nconst service = strapi.plugin(\"import-export-entries\").service(\"export\");\n\n/**\n * Method exportData.\n */\nawait service.exportData(\n  options: {\n    /**\n     * Slug of the model to export.\n     * - \"media\" is a custom slug to specifically export media.\n     */\n    slug: \"media\" | string;\n    /**\n     * Export format.\n     * - csv\n     * - json\n     * - json-v2: json in the new json file format (see section `Importing Data`)\n     */\n    exportFormat: \"csv\" | \"json\" | \"json-v2\";\n    /** Search query used to select the entries to export. The package `qs` is used to parse the query. */\n    search?: string;\n    /** Whether to apply the search query. */\n    applySearch?: boolean;\n    /** Whether to export relations as id instead of plain objects. */\n    relationsAsId?: boolean;\n    /** Deepness of the exported data. */\n    deepness?: number;\n  }\n) : Promise<string>;\n```\n\n## Content API\n\nData can be imported/exported through the content api. Endpoints have to be enabled in _Settings > Users & Permissions plugin > Roles_.\n\n```ts\n/*****************************\n * Import data\n *\n * POST /api/import-export-entries/content/import\n ****************************/\n\ntype RouteParams = {\n  /** Slug of the model to export. */\n  slug: string;\n  /**\n   * Data to import.\n   * if `format` is \"csv\", data must be a string.\n   * if `format` is \"json\", data must be an object or an array of objects.\n   * */\n  data: string | Object | Object[];\n  /** Format of the passed data to import. */\n  format: 'csv' | 'json';\n  /** Name of the field to use as a unique identifier for entries. Default: \"id\" */\n  idField?: string;\n};\n\ntype RouteReturn = {\n  /** Array of failed imports. */\n  failures: {\n    /** Error raised during import. */\n    error: string;\n    /** Data for which the import failed. */\n    data: Object;\n  }[];\n};\n```\n\n```ts\n/*****************************\n * Export data\n *\n * POST /api/import-export-entries/content/export/contentTypes\n ****************************/\n\ntype RouteParams = {\n  /** Slug of the model to export. */\n  slug: string;\n  /** Format to use to export the data. */\n  exportFormat: 'csv' | 'json';\n  /** Search query used to select the entries to export. The package `qs` is used to parse the query. Default: \"\" */\n  search?: string;\n  /** Whether to apply the search query. Default: false */\n  applySearch?: boolean;\n  /** Whether to export relations as id instead of plain objects. Default: false */\n  relationsAsId?: boolean;\n  /** Deepness of the exported data. Default: 5 */\n  deepness?: number;\n};\n\ntype RouteReturn = {\n  /** Exported data. */\n  data: string;\n};\n```\n\n## Webhook\n\nAt the moment, the webhook is triggered only for media creation, update and deletion. It is not triggered for other data.\n\n# Importing Data\n\n## JSON v2\n\nJSON v2 introduces a new supported file structure. Data is flattened and dependencies only relies on `id`s (`object`s are not supported in this new version). Collection types, single types, media and components are all treated the same for ease of use.\n\nHere is an example:\n\n```js\n{\n  \"version\": 2, // required for the import to work properly.\n  \"data\": {\n    // Each collection has a dedicated key in the `data` property.\n    \"api::collection-name.collection-name\": {\n      // Sub keys are `id`s of imported entries and values hold the data of the entries to import.\n      \"1\": {\n        \"id\": 1\n        //...\n      },\n      \"2\": {\n        \"id\": 2\n        //...\n      }\n    },\n    \"api::other-collection-name.other-collection-name\": {\n      \"1\": {\n        \"id\": 1,\n        // Relations are specified by `id`s.\n        \"collectionAbove\": [1]\n        //...\n      },\n      \"2\": {\n        \"id\": 2,\n        \"collectionAbove\": [1, 2]\n        //...\n      }\n    },\n    // Import medias.\n    \"plugin::upload.file\": {\n      \"1\": {\n        \"id\": 1\n        //...\n      },\n      \"2\": {\n        \"id\": 2\n        //...\n      }\n    },\n    // Import components.\n    \"my.component\": {\n      \"1\": {\n        \"id\": 1\n        //...\n      },\n      \"2\": {\n        \"id\": 2\n        //...\n      }\n    }\n  }\n}\n```\n\n## JSON v1 (deprecated)\n\nThe expected import data structure:\n\n## Relation:\n\n### `object`\n\nthe relation is searched in db by `id`. If an entry is found, it is updated with the provided data. Otherwise, it is created.\n\n### `number`\n\nThe relation is treated as an id.\n\n## Media:\n\n### `object`\n\nthe media must have an `id`, `hash`, `name` or `url` property. First the media is searched by `id`, then by `hash`, then by `name` and finally imported from `url` if not found previously.\n\nWhen imported by `url`, the `hash` and `name` of the file are deduced from the `url` (the `hash` is also deduced because Strapi exports files with their `hash` in the `url` instead of the `name`). The `hash` and `name` are used to find the media in db. First the media is searched by `hash`, then by `name` and used if found. Otherwise, the media is uploaded to the db by downloading the file from the `url`.\n\n> ⚠️ Check the server has access to the `url`.\n\nWhen imported by `url`, extra data can be provided to enhance the created file:\n\n- `id` (_defaults to an auto generated `id`_)\n- `name` (_defaults to the `name` deduced from the url_)\n- `caption` (_defaults to `\"\"`_)\n- `alternativeText` (_defaults to `\"\"`_)\n\n### Examples\n\n- `{ id: 1 }`\n- `{ hash: \"alpaga.jpg\" }`\n- `{ name: \"alpaga.jpg\" }`\n- `{ url: \"https://www.thetimes.co.uk/imageserver/image/alpaga.jpg\" }` (Deduced file `hash` is `alpaga` and deduced `name` is `imageserver-image-alpaga.jpg`)\n- `{ url: \"http://localhost:1337/alpaga.jpg\" }` (Deduced file `hash` is `alpaga` and deduced `name` is `alpaga.jpg`)\n- `{ id: 734, url: \"http://localhost:1337/alpaga.jpg\", name: \"Alpacool\", caption: \"Alpacool In Da Hood\", alternativeText: \"Alpacool in da hood\" }`\n\n### `string`\n\nSame as above, except the media provided is treated as a `url`.\n\n- `\"https://www.thetimes.co.uk/imageserver/image/alpaga.jpg\"` (Deduced file `hash` is `alpaga` and deduced `name` is `imageserver-image-alpaga.jpg`)\n- `\"http://localhost:1337/alpaga.jpg\"` (Deduced file `hash` is `alpaga` and deduced `name` is `alpaga.jpg`)\n\n### `number`\n\nThe media is treated as an id.\n\n- `7`\n\n## Related Plugins\n\n- [Strapi Plugin Request Id](https://github.com/Baboo7/strapi-plugin-request-id): Add a unique id to each request made to your server and track your users' activity in the logs\n\n## Author\n\nBaboo - [@Baboo7](https://github.com/Baboo7)\n\n## Acknowledgments\n\nThis plugin (and especially this README) took strong inspiration from the [strapi-plugin-import-export-content](https://github.com/EdisonPeM/strapi-plugin-import-export-content#readme) from [EdisonPeM](https://github.com/EdisonPeM).\n","readmeFilename":"README.md"}