This commit is contained in:
Stefan Pejcic
2024-05-08 19:52:27 +02:00
parent 9c8d080b57
commit 80303fadd5
2509 changed files with 0 additions and 594172 deletions

View File

@@ -1,4 +0,0 @@
{
"email": "johndoe@refine.dev",
"password": "JohnDoe-refine-dev-123"
}

View File

@@ -1,302 +0,0 @@
[
{
"id": 1,
"title": "Ut Voluptatem Est",
"content": "Repellendus temporibus provident nobis. Non adipisci quod et est dolorem sed qui. A ut omnis. Et perspiciatis quibusdam maiores aliquid est fugit nam odit. Aut aliquam consectetur deleniti commodi velit. Eum eum aperiam voluptate quos quo. Ut quia doloribus a. Molestiae non est fugit enim fugiat non ea quas accusamus. Consequuntur voluptatem nesciunt dolorum expedita optio deserunt. Illo dolorem et similique.",
"category": {
"id": 1
},
"status": "published",
"createdAt": "2022-06-12T11:03:09.829Z"
},
{
"id": 2,
"title": "Sequi Quod Repellendus",
"content": "Odit natus dolor consequatur tempore recusandae exercitationem. Unde dolores aut. Dolor ipsam quam quis modi sint. Dolor itaque voluptatum non qui ratione nisi ullam assumenda. Nisi et aut incidunt fuga aut deserunt. Labore sit ut quia vero vel et sed suscipit. Voluptatum maiores adipisci vel molestiae minima in enim et. Repellendus autem quis nisi vero vel consectetur laborum. Similique quos voluptates officiis velit. Sapiente nihil ut ipsa autem.",
"category": {
"id": 2
},
"status": "published",
"createdAt": "2021-10-11T08:03:00.155Z"
},
{
"id": 3,
"title": "Ad Enim Blanditiis",
"content": "Illo et facilis deleniti voluptatem neque et optio. Eum rerum distinctio dolor omnis sequi expedita dicta reprehenderit quaerat. In eaque odio dicta ullam cumque qui neque molestias. Libero vitae quo pariatur tempore. Excepturi fuga pariatur est sint quasi. Expedita reiciendis laboriosam explicabo ratione quia laboriosam. Alias ratione ea. Minus ut nisi ad ex eligendi id vero soluta unde. Aut aut placeat reprehenderit voluptatem ut. Voluptatibus laborum modi ducimus.",
"category": {
"id": 1
},
"status": "rejected",
"createdAt": "2022-04-16T16:34:03.319Z"
},
{
"id": 4,
"title": "Dolores Modi Natus",
"content": "Magnam pariatur ut ab accusamus minus labore commodi. Excepturi natus hic aut illum mollitia. Ipsum incidunt adipisci rerum veritatis quae rerum. Ipsum blanditiis quisquam ea quia et in. Exercitationem rerum in. Ut quo quia et esse expedita consequatur sint culpa voluptas. Sed optio voluptas totam id aut odio voluptatum sequi. Velit aut ea esse alias voluptatem omnis numquam aut eligendi. Voluptatem natus suscipit. Praesentium enim reiciendis nihil delectus eum totam fugit accusantium fuga.",
"category": {
"id": 2
},
"status": "published",
"createdAt": "2021-05-20T02:19:56.513Z"
},
{
"id": 5,
"title": "Repellendus Aspernatur Porro",
"content": "Blanditiis voluptas suscipit harum. Nobis aspernatur quas. Asperiores optio id iste quis sint in modi. Ea explicabo velit numquam sed natus sed aliquam. Modi sapiente expedita suscipit neque reprehenderit qui et officiis. Quis et iusto quis veniam. Ut quis quidem incidunt adipisci non et ad ut. Quis quo illum nemo. Totam esse ut quisquam dolorum explicabo. Ea mollitia sed eos ducimus saepe ratione et doloremque.",
"category": {
"id": 3
},
"status": "rejected",
"createdAt": "2022-01-09T07:01:11.195Z"
},
{
"id": 6,
"title": "Natus Ut Distinctio",
"content": "Sit ut eos nulla. Assumenda ut aut aspernatur placeat rerum numquam quasi quos. Aut nihil ratione assumenda quos voluptatem. Repudiandae excepturi vel qui vel facilis non blanditiis asperiores. Et nesciunt consequatur natus incidunt sit accusantium maxime quo. Qui modi maxime est est aut ipsam et illo nihil. Voluptas enim quod tempora sit eveniet atque. Consectetur aperiam quisquam quis rerum. Maiores repellendus dolor et earum consequuntur sit qui dolor minima. Sint vitae veritatis qui consequuntur nemo impedit et.",
"category": {
"id": 4
},
"status": "published",
"createdAt": "2023-02-01T15:32:15.719Z"
},
{
"id": 7,
"title": "Vel Labore Sint",
"content": "Quasi magni asperiores laborum accusantium debitis in voluptas quia. Velit mollitia earum magnam maxime aut. Enim at assumenda quidem vel libero facilis vel. Enim voluptate maiores. Quia ut odio fugit tempore iste qui et. Sit eaque voluptate omnis dolorem perspiciatis deleniti non qui assumenda. Possimus et rerum nam possimus inventore dolorem corrupti earum. Architecto consequuntur et cupiditate. Molestiae nisi facere qui ut saepe quis. Eius adipisci tempore itaque sed odio veniam harum quia.",
"category": {
"id": 5
},
"status": "rejected",
"createdAt": "2022-02-27T09:01:32.679Z"
},
{
"id": 8,
"title": "Minus Nulla Molestias",
"content": "Qui velit dolorem fuga ad quas omnis harum. Ipsam sint ipsam quos nam sed adipisci. Aut adipisci asperiores tenetur laborum accusantium sint atque. Optio delectus fugiat iusto ut consequatur non delectus sit. Aut corrupti est sequi rerum asperiores fuga aut velit laborum. Quaerat magnam fuga dolores. Vel tenetur neque sapiente. Soluta quia autem delectus eos eveniet. Qui quis et velit molestiae enim qui explicabo dolor. Sit placeat molestias fugiat optio repellat voluptas.",
"category": {
"id": 6
},
"status": "rejected",
"createdAt": "2022-11-07T12:30:27.331Z"
},
{
"id": 9,
"title": "Quibusdam Ut Natus",
"content": "Minus nam fugiat veritatis sequi ut. Iure nisi hic exercitationem rerum tempore earum. Rerum velit nemo est omnis nulla consequatur excepturi aut. Iusto ut autem porro commodi non. Et excepturi et aliquid alias qui minima nostrum deleniti. Ut qui consequatur voluptatem. Recusandae eos et odit neque. Non quaerat voluptatem molestiae necessitatibus. Et omnis dolore aperiam delectus. Rerum et et libero.",
"category": {
"id": 7
},
"status": "draft",
"createdAt": "2021-12-18T05:22:45.857Z"
},
{
"id": 10,
"title": "Nam Voluptas Ipsum",
"content": "Eum quaerat nostrum nulla consequatur quia quod autem minus. Quis omnis corrupti qui dolores. Non soluta suscipit. Ut distinctio eius consequuntur unde ab vel nobis sint nostrum. Natus omnis omnis debitis. Porro sit rerum vitae officiis dolorem veniam occaecati amet. Vitae et facilis provident enim et perferendis dolorum voluptatum. Fugiat provident explicabo ut libero aperiam dolore voluptatem. Et reiciendis error cupiditate blanditiis ea velit in incidunt. Doloribus et quis totam.",
"category": {
"id": 8
},
"status": "rejected",
"createdAt": "2021-11-21T05:29:05.942Z"
},
{
"id": 11,
"title": "Nam Placeat Expedita",
"content": "Et iusto vel aut animi mollitia. Nesciunt nobis sunt et dolore soluta. Dolore doloremque qui vero ut. Aperiam maiores ea. Consequuntur omnis eos. Ipsam reprehenderit cupiditate maiores est fuga dolorum repellendus quisquam dolorem. Consequatur ea reprehenderit nulla quia occaecati laboriosam. Maiores dicta in tempora. Tempora et adipisci aspernatur est. Ipsum et molestiae illum fugiat.",
"category": {
"id": 9
},
"status": "rejected",
"createdAt": "2023-05-05T19:52:59.535Z"
},
{
"id": 12,
"title": "Rerum Voluptatem Sunt",
"content": "Voluptas et cumque numquam. Suscipit eum cumque cupiditate vel possimus voluptatibus est ut. Optio molestiae nisi officiis sint sed vel provident accusantium. Omnis voluptatum officiis voluptatem numquam necessitatibus quisquam. A sit quae numquam numquam est. Aut in placeat. Modi quod et quaerat autem nemo. Amet in laudantium. Quis adipisci facere. Sed suscipit labore.",
"category": {
"id": 4
},
"status": "rejected",
"createdAt": "2021-06-26T00:07:45.503Z"
},
{
"id": 13,
"title": "In Sequi Recusandae",
"content": "Quia sit nulla occaecati enim. Totam rerum delectus. Quidem dolorum a rerum odio. Et molestias magnam amet sint soluta nemo. Dolore incidunt voluptatum quo recusandae quis consectetur est rerum nobis. Sit facere dignissimos libero et sint unde nam atque sunt. Tenetur facilis eos animi animi possimus. Qui maxime ut eum. Quas accusantium non rerum accusantium id soluta. Illum fugiat similique cumque.",
"category": {
"id": 2
},
"status": "draft",
"createdAt": "2021-10-02T13:20:44.138Z"
},
{
"id": 14,
"title": "Impedit Maiores Consequatur",
"content": "Quibusdam sed incidunt assumenda. Nulla unde optio. Reiciendis placeat provident aut culpa aut nam et quis dolores. Ipsa velit non enim est earum quae velit totam corporis. Quod unde recusandae. Dolores et sed vel illo perferendis vitae sunt et. Cumque voluptatem dolores aut illum. Qui voluptates id ut est maxime adipisci rerum. Enim porro quo repudiandae dolore enim incidunt iste. Perferendis adipisci dicta harum.",
"category": {
"id": 3
},
"status": "draft",
"createdAt": "2021-06-06T15:12:04.543Z"
},
{
"id": 15,
"title": "Deserunt Ut Enim",
"content": "Explicabo quaerat officia rerum nobis non sint. Fugit blanditiis ipsum et tempora iure eaque quo. Ratione sed voluptatem rerum ad illum veniam sint. Excepturi aliquam et. Dolor reprehenderit reiciendis quia voluptatem accusamus odio et et. Voluptatem maxime enim reprehenderit veritatis voluptatem maxime. Non quia adipisci molestiae dolorem voluptatum ipsam libero sed. Illo et voluptatem. Atque sit eos et fugit fugiat quia sed aliquam eveniet. Veniam nulla dolorem exercitationem blanditiis consequatur ipsam.",
"category": {
"id": 9
},
"status": "draft",
"createdAt": "2022-04-24T18:07:20.293Z"
},
{
"id": 16,
"title": "Ut Voluptatem Est",
"content": "Repellendus temporibus provident nobis. Non adipisci quod et est dolorem sed qui. A ut omnis. Et perspiciatis quibusdam maiores aliquid est fugit nam odit. Aut aliquam consectetur deleniti commodi velit. Eum eum aperiam voluptate quos quo. Ut quia doloribus a. Molestiae non est fugit enim fugiat non ea quas accusamus. Consequuntur voluptatem nesciunt dolorum expedita optio deserunt. Illo dolorem et similique.",
"category": {
"id": 1
},
"status": "published",
"createdAt": "2022-06-12T11:03:09.829Z"
},
{
"id": 17,
"title": "Sequi Quod Repellendus",
"content": "Odit natus dolor consequatur tempore recusandae exercitationem. Unde dolores aut. Dolor ipsam quam quis modi sint. Dolor itaque voluptatum non qui ratione nisi ullam assumenda. Nisi et aut incidunt fuga aut deserunt. Labore sit ut quia vero vel et sed suscipit. Voluptatum maiores adipisci vel molestiae minima in enim et. Repellendus autem quis nisi vero vel consectetur laborum. Similique quos voluptates officiis velit. Sapiente nihil ut ipsa autem.",
"category": {
"id": 2
},
"status": "published",
"createdAt": "2021-10-11T08:03:00.155Z"
},
{
"id": 18,
"title": "Ad Enim Blanditiis",
"content": "Illo et facilis deleniti voluptatem neque et optio. Eum rerum distinctio dolor omnis sequi expedita dicta reprehenderit quaerat. In eaque odio dicta ullam cumque qui neque molestias. Libero vitae quo pariatur tempore. Excepturi fuga pariatur est sint quasi. Expedita reiciendis laboriosam explicabo ratione quia laboriosam. Alias ratione ea. Minus ut nisi ad ex eligendi id vero soluta unde. Aut aut placeat reprehenderit voluptatem ut. Voluptatibus laborum modi ducimus.",
"category": {
"id": 1
},
"status": "rejected",
"createdAt": "2022-04-16T16:34:03.319Z"
},
{
"id": 19,
"title": "Dolores Modi Natus",
"content": "Magnam pariatur ut ab accusamus minus labore commodi. Excepturi natus hic aut illum mollitia. Ipsum incidunt adipisci rerum veritatis quae rerum. Ipsum blanditiis quisquam ea quia et in. Exercitationem rerum in. Ut quo quia et esse expedita consequatur sint culpa voluptas. Sed optio voluptas totam id aut odio voluptatum sequi. Velit aut ea esse alias voluptatem omnis numquam aut eligendi. Voluptatem natus suscipit. Praesentium enim reiciendis nihil delectus eum totam fugit accusantium fuga.",
"category": {
"id": 2
},
"status": "published",
"createdAt": "2021-05-20T02:19:56.513Z"
},
{
"id": 20,
"title": "Repellendus Aspernatur Porro",
"content": "Blanditiis voluptas suscipit harum. Nobis aspernatur quas. Asperiores optio id iste quis sint in modi. Ea explicabo velit numquam sed natus sed aliquam. Modi sapiente expedita suscipit neque reprehenderit qui et officiis. Quis et iusto quis veniam. Ut quis quidem incidunt adipisci non et ad ut. Quis quo illum nemo. Totam esse ut quisquam dolorum explicabo. Ea mollitia sed eos ducimus saepe ratione et doloremque.",
"category": {
"id": 3
},
"status": "rejected",
"createdAt": "2022-01-09T07:01:11.195Z"
},
{
"id": 21,
"title": "Natus Ut Distinctio",
"content": "Sit ut eos nulla. Assumenda ut aut aspernatur placeat rerum numquam quasi quos. Aut nihil ratione assumenda quos voluptatem. Repudiandae excepturi vel qui vel facilis non blanditiis asperiores. Et nesciunt consequatur natus incidunt sit accusantium maxime quo. Qui modi maxime est est aut ipsam et illo nihil. Voluptas enim quod tempora sit eveniet atque. Consectetur aperiam quisquam quis rerum. Maiores repellendus dolor et earum consequuntur sit qui dolor minima. Sint vitae veritatis qui consequuntur nemo impedit et.",
"category": {
"id": 4
},
"status": "published",
"createdAt": "2023-02-01T15:32:15.719Z"
},
{
"id": 22,
"title": "Vel Labore Sint",
"content": "Quasi magni asperiores laborum accusantium debitis in voluptas quia. Velit mollitia earum magnam maxime aut. Enim at assumenda quidem vel libero facilis vel. Enim voluptate maiores. Quia ut odio fugit tempore iste qui et. Sit eaque voluptate omnis dolorem perspiciatis deleniti non qui assumenda. Possimus et rerum nam possimus inventore dolorem corrupti earum. Architecto consequuntur et cupiditate. Molestiae nisi facere qui ut saepe quis. Eius adipisci tempore itaque sed odio veniam harum quia.",
"category": {
"id": 5
},
"status": "rejected",
"createdAt": "2022-02-27T09:01:32.679Z"
},
{
"id": 23,
"title": "Minus Nulla Molestias",
"content": "Qui velit dolorem fuga ad quas omnis harum. Ipsam sint ipsam quos nam sed adipisci. Aut adipisci asperiores tenetur laborum accusantium sint atque. Optio delectus fugiat iusto ut consequatur non delectus sit. Aut corrupti est sequi rerum asperiores fuga aut velit laborum. Quaerat magnam fuga dolores. Vel tenetur neque sapiente. Soluta quia autem delectus eos eveniet. Qui quis et velit molestiae enim qui explicabo dolor. Sit placeat molestias fugiat optio repellat voluptas.",
"category": {
"id": 6
},
"status": "rejected",
"createdAt": "2022-11-07T12:30:27.331Z"
},
{
"id": 24,
"title": "Quibusdam Ut Natus",
"content": "Minus nam fugiat veritatis sequi ut. Iure nisi hic exercitationem rerum tempore earum. Rerum velit nemo est omnis nulla consequatur excepturi aut. Iusto ut autem porro commodi non. Et excepturi et aliquid alias qui minima nostrum deleniti. Ut qui consequatur voluptatem. Recusandae eos et odit neque. Non quaerat voluptatem molestiae necessitatibus. Et omnis dolore aperiam delectus. Rerum et et libero.",
"category": {
"id": 7
},
"status": "draft",
"createdAt": "2021-12-18T05:22:45.857Z"
},
{
"id": 25,
"title": "Nam Voluptas Ipsum",
"content": "Eum quaerat nostrum nulla consequatur quia quod autem minus. Quis omnis corrupti qui dolores. Non soluta suscipit. Ut distinctio eius consequuntur unde ab vel nobis sint nostrum. Natus omnis omnis debitis. Porro sit rerum vitae officiis dolorem veniam occaecati amet. Vitae et facilis provident enim et perferendis dolorum voluptatum. Fugiat provident explicabo ut libero aperiam dolore voluptatem. Et reiciendis error cupiditate blanditiis ea velit in incidunt. Doloribus et quis totam.",
"category": {
"id": 8
},
"status": "rejected",
"createdAt": "2021-11-21T05:29:05.942Z"
},
{
"id": 26,
"title": "Nam Placeat Expedita",
"content": "Et iusto vel aut animi mollitia. Nesciunt nobis sunt et dolore soluta. Dolore doloremque qui vero ut. Aperiam maiores ea. Consequuntur omnis eos. Ipsam reprehenderit cupiditate maiores est fuga dolorum repellendus quisquam dolorem. Consequatur ea reprehenderit nulla quia occaecati laboriosam. Maiores dicta in tempora. Tempora et adipisci aspernatur est. Ipsum et molestiae illum fugiat.",
"category": {
"id": 9
},
"status": "rejected",
"createdAt": "2023-05-05T19:52:59.535Z"
},
{
"id": 27,
"title": "Rerum Voluptatem Sunt",
"content": "Voluptas et cumque numquam. Suscipit eum cumque cupiditate vel possimus voluptatibus est ut. Optio molestiae nisi officiis sint sed vel provident accusantium. Omnis voluptatum officiis voluptatem numquam necessitatibus quisquam. A sit quae numquam numquam est. Aut in placeat. Modi quod et quaerat autem nemo. Amet in laudantium. Quis adipisci facere. Sed suscipit labore.",
"category": {
"id": 4
},
"status": "rejected",
"createdAt": "2021-06-26T00:07:45.503Z"
},
{
"id": 28,
"title": "In Sequi Recusandae",
"content": "Quia sit nulla occaecati enim. Totam rerum delectus. Quidem dolorum a rerum odio. Et molestias magnam amet sint soluta nemo. Dolore incidunt voluptatum quo recusandae quis consectetur est rerum nobis. Sit facere dignissimos libero et sint unde nam atque sunt. Tenetur facilis eos animi animi possimus. Qui maxime ut eum. Quas accusantium non rerum accusantium id soluta. Illum fugiat similique cumque.",
"category": {
"id": 2
},
"status": "draft",
"createdAt": "2021-10-02T13:20:44.138Z"
},
{
"id": 29,
"title": "Impedit Maiores Consequatur",
"content": "Quibusdam sed incidunt assumenda. Nulla unde optio. Reiciendis placeat provident aut culpa aut nam et quis dolores. Ipsa velit non enim est earum quae velit totam corporis. Quod unde recusandae. Dolores et sed vel illo perferendis vitae sunt et. Cumque voluptatem dolores aut illum. Qui voluptates id ut est maxime adipisci rerum. Enim porro quo repudiandae dolore enim incidunt iste. Perferendis adipisci dicta harum.",
"category": {
"id": 3
},
"status": "draft",
"createdAt": "2021-06-06T15:12:04.543Z"
},
{
"id": 30,
"title": "Deserunt Ut Enim",
"content": "Explicabo quaerat officia rerum nobis non sint. Fugit blanditiis ipsum et tempora iure eaque quo. Ratione sed voluptatem rerum ad illum veniam sint. Excepturi aliquam et. Dolor reprehenderit reiciendis quia voluptatem accusamus odio et et. Voluptatem maxime enim reprehenderit veritatis voluptatem maxime. Non quia adipisci molestiae dolorem voluptatum ipsam libero sed. Illo et voluptatem. Atque sit eos et fugit fugiat quia sed aliquam eveniet. Veniam nulla dolorem exercitationem blanditiis consequatur ipsam.",
"category": {
"id": 9
},
"status": "draft",
"createdAt": "2022-04-24T18:07:20.293Z"
}
]

View File

@@ -1,42 +0,0 @@
[
{
"id": 1,
"title": "Sint Ipsam Tempora"
},
{
"id": 2,
"title": "Neque Consequuntur Dicta"
},
{
"id": 3,
"title": "Totam Similique Quidem"
},
{
"id": 4,
"title": "Enim Perferendis Praesentium"
},
{
"id": 5,
"title": "Neque Quidem Est"
},
{
"id": 6,
"title": "Cumque Cumque Fuga"
},
{
"id": 7,
"title": "Beatae Voluptatem Voluptas"
},
{
"id": 8,
"title": "Dolor Laudantium Quia"
},
{
"id": 9,
"title": "Sint Libero Sint"
},
{
"id": 10,
"title": "Placeat Excepturi Ad"
}
]

View File

@@ -1,4 +0,0 @@
{
"email": "demo@refine.dev",
"password": "demodemo"
}

View File

@@ -1,231 +0,0 @@
{
"data": {
"blog_posts": [
{
"id": "1",
"title": "Sed ante. Vivamus tortor. Duis mattis egestas metus.",
"category": {
"id": "1",
"title": "neque vestibulum"
},
"category_id": "1",
"content": "Phasellus sit amet erat. Nulla tempus. Vivamus in felis eu sapien cursus vestibulum.",
"created_at": "2023-03-20T09:57:27.548697+00:00"
},
{
"id": "2",
"title": "Phasellus sit amet erat.",
"category": {
"id": "2",
"title": "enim lorem ipsum"
},
"category_id": "2",
"content": "Duis bibendum, felis sed interdum venenatis, turpis enim blandit mi, in porttitor pede justo eu massa. Donec dapibus. Duis at velit eu est congue elementum.\n\nIn hac habitasse platea dictumst. Morbi vestibulum, velit id pretium iaculis, diam erat fermentum justo, nec condimentum neque sapien placerat ante. Nulla justo.\n\nAliquam quis turpis eget elit sodales scelerisque. Mauris sit amet eros. Suspendisse accumsan tortor quis turpis.",
"created_at": "2023-03-20T09:57:27.548697+00:00"
},
{
"id": "3",
"title": "Nam ultrices, libero non mattis pulvinar, nulla pede ullamcorper augue, a suscipit nulla elit ac nulla. Sed vel enim sit amet nunc viverra dapibus.",
"category": {
"id": "3",
"title": "vivamus vel"
},
"category_id": "3",
"content": "Suspendisse potenti. In eleifend quam a odio. In hac habitasse platea dictumst.\n\nMaecenas ut massa quis augue luctus tincidunt. Nulla mollis molestie lorem. Quisque ut erat.",
"created_at": "2023-03-20T09:57:27.548697+00:00"
},
{
"id": "4",
"title": "Suspendisse potenti. In eleifend quam a odio. In hac habitasse platea dictumst.",
"category": {
"id": "4",
"title": "aaaaaaaaaarhoncus"
},
"category_id": "4",
"content": "Proin leo odio, porttitor id, consequat in, consequat ut, nulla. Sed accumsan felis. Ut at dolor quis odio consequat varius.",
"created_at": "2023-03-20T09:57:27.548697+00:00"
},
{
"id": "5",
"title": "In hac habitasse platea dictumst. Morbi vestibulum, velit id pretium iaculis, diam erat fermentum justo, nec condimentum neque sapien placerat ante. Nulla justo.",
"category": {
"id": "5",
"title": "turpis adipiscing lorem"
},
"category_id": "5",
"content": "Duis consequat dui nec nisi volutpat eleifend. Donec ut dolor. Morbi vel lectus in quam fringilla rhoncus.\n\nMauris enim leo, rhoncus sed, vestibulum sit amet, cursus id, turpis. Integer aliquet, massa id lobortis convallis, tortor risus dapibus augue, vel accumsan tellus nisi eu orci. Mauris lacinia sapien quis libero.\n\nNullam sit amet turpis elementum ligula vehicula consequat. Morbi a ipsum. Integer a nibh.",
"created_at": "2023-03-20T09:57:27.548697+00:00"
},
{
"id": "6",
"title": "Maecenas rhoncus aliquam lacus. Morbi quis tortor id nulla ultrices aliquet.",
"category": {
"id": "6",
"title": "aaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"category_id": "6",
"content": "Vestibulum quam sapien, varius ut, blandit non, interdum in, ante. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Duis faucibus accumsan odio. Curabitur convallis.\n\nDuis consequat dui nec nisi volutpat eleifend. Donec ut dolor. Morbi vel lectus in quam fringilla rhoncus.\n\nMauris enim leo, rhoncus sed, vestibulum sit amet, cursus id, turpis. Integer aliquet, massa id lobortis convallis, tortor risus dapibus augue, vel accumsan tellus nisi eu orci. Mauris lacinia sapien quis libero.",
"created_at": "2023-03-20T09:57:27.548697+00:00"
},
{
"id": "7",
"title": "Etiam pretium iaculis justo.",
"category": {
"id": "7",
"title": "test category"
},
"category_id": "7",
"content": "In congue. Etiam justo. Etiam pretium iaculis justo.\n\nIn hac habitasse platea dictumst. Etiam faucibus cursus urna. Ut tellus.\n\nNulla ut erat id mauris vulputate elementum. Nullam varius. Nulla facilisi.",
"created_at": "2023-03-20T09:57:27.548697+00:00"
},
{
"id": "8",
"title": "Pellentesque at nulla. Suspendisse potenti.",
"category": {
"id": "8",
"title": "vulputate elementum nullam 2"
},
"category_id": "8",
"content": "Nullam sit amet turpis elementum ligula vehicula consequat. Morbi a ipsum. Integer a nibh.",
"created_at": "2023-03-20T09:57:27.548697+00:00"
},
{
"id": "9",
"title": "Integer ac neque. Duis bibendum. Morbi non quam nec dui luctus rutrum.",
"category": {
"id": "9",
"title": "lacinia eget tincidunt"
},
"category_id": "9",
"content": "Duis bibendum, felis sed interdum venenatis, turpis enim blandit mi, in porttitor pede justo eu massa. Donec dapibus. Duis at velit eu est congue elementum.",
"created_at": "2023-03-20T09:57:27.548697+00:00"
},
{
"id": "10",
"title": "Aliquam non mauris. Morbi non lectus. Aliquam sit amet diam in magna bibendum imperdiet.",
"category": {
"id": "10",
"title": "aliquam erat volutpat"
},
"category_id": "10",
"content": "In hac habitasse platea dictumst. Etiam faucibus cursus urna. Ut tellus.Nulla ut erat id mauris vulputate elementum. Nullam varius. Nulla facilisi.",
"created_at": "2023-03-20T09:57:27.548697+00:00"
},
{
"id": "11",
"title": "Praesent lectus.",
"category": {
"id": "1",
"title": "aaaaaaaaaarhoncus"
},
"category_id": "1",
"content": "Cras mi pede, malesuada in, imperdiet et, commodo vulputate, justo. In blandit ultrices enim. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.\n\nProin interdum mauris non ligula pellentesque ultrices. Phasellus id sapien in sapien iaculis congue. Vivamus metus arcu, adipiscing molestie, hendrerit at, vulputate vitae, nisl.",
"created_at": "2023-03-20T09:57:27.548697+00:00"
},
{
"id": "12",
"title": "Nullam orci pede, venenatis non, sodales sed, tincidunt eu, felis. Fusce posuere felis sed lacus.",
"category": {
"id": "2",
"title": "vulputate elementum nullam 2"
},
"category_id": "2",
"content": "Aliquam quis turpis eget elit sodales scelerisque. Mauris sit amet eros. Suspendisse accumsan tortor quis turpis.\n\nSed ante. Vivamus tortor. Duis mattis egestas metus.\n\nAenean fermentum. Donec ut mauris eget massa tempor convallis. Nulla neque libero, convallis eget, eleifend luctus, ultricies eu, nibh.",
"created_at": "2023-03-20T09:57:27.548697+00:00"
},
{
"id": "13",
"title": "Donec ut mauris eget massa tempor convallis. Nulla neque libero, convallis eget, eleifend luctus, ultricies eu, nibh.",
"category": {
"id": "3",
"title": "sed accumsan felis"
},
"category_id": "3",
"content": "Duis aliquam convallis nunc. Proin at turpis a pede posuere nonummy. Integer non velit.\n\nDonec diam neque, vestibulum eget, vulputate ut, ultrices vel, augue. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec pharetra, magna vestibulum aliquet ultrices, erat tortor sollicitudin mi, sit amet lobortis sapien sapien non mi. Integer ac neque.",
"created_at": "2023-03-20T09:57:27.548697+00:00"
},
{
"id": "14",
"title": "Praesent blandit. Nam nulla. Integer pede justo, lacinia eget, tincidunt eget, tempus vel, pede.",
"category": {
"id": "4",
"title": "enim lorem ipsum"
},
"category_id": "4",
"content": "Morbi non lectus. Aliquam sit amet diam in magna bibendum imperdiet. Nullam orci pede, venenatis non, sodales sed, tincidunt eu, felis.\n\nFusce posuere felis sed lacus. Morbi sem mauris, laoreet ut, rhoncus aliquet, pulvinar sed, nisl. Nunc rhoncus dui vel sem.",
"created_at": "2023-03-20T09:57:27.548697+00:00"
},
{
"id": "15",
"title": "In hac habitasse platea dictumst. Maecenas ut massa quis augue luctus tincidunt.",
"category": {
"id": "5",
"title": "vulputate elementum nullam 2"
},
"category_id": "5",
"content": "Pellentesque at nulla. Suspendisse potenti. Cras in purus eu magna vulputate luctus.\n\nCum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus vestibulum sagittis sapien. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.",
"created_at": "2023-03-20T09:57:27.548697+00:00"
},
{
"id": "16",
"title": "Morbi odio odio, elementum eu, interdum eu, tincidunt in, leo.",
"category": {
"id": "6",
"title": "blandit ultrices enim"
},
"category_id": "6",
"content": "Duis bibendum, felis sed interdum venenatis, turpis enim blandit mi, in porttitor pede justo eu massa. Donec dapibus. Duis at velit eu est congue elementum.\n\nIn hac habitasse platea dictumst. Morbi vestibulum, velit id pretium iaculis, diam erat fermentum justo, nec condimentum neque sapien placerat ante. Nulla justo.",
"created_at": "2023-03-20T09:57:27.548697+00:00"
},
{
"id": "17",
"title": "Praesent lectus.",
"category": {
"id": "7",
"title": "amet turpis elementum"
},
"category_id": "7",
"content": "In hac habitasse platea dictumst. Morbi vestibulum, velit id pretium iaculis, diam erat fermentum justo, nec condimentum neque sapien placerat ante. Nulla justo.",
"created_at": "2023-03-20T09:57:27.548697+00:00"
},
{
"id": "18",
"title": "Proin risus. Praesent lectus.",
"category": {
"id": "8",
"title": "ipsum primis in"
},
"category_id": "8",
"content": "Etiam vel augue. Vestibulum rutrum rutrum neque. Aenean auctor gravida sem.\n\nPraesent id massa id nisl venenatis lacinia. Aenean sit amet justo. Morbi ut odio.",
"created_at": "2023-03-20T09:57:27.548697+00:00"
},
{
"id": "19",
"title": "Integer non velit.",
"category": {
"id": "9",
"title": "lorem integer tincidunt"
},
"category_id": "9",
"content": "Fusce posuere felis sed lacus. Morbi sem mauris, laoreet ut, rhoncus aliquet, pulvinar sed, nisl. Nunc rhoncus dui vel sem.\n\nSed sagittis. Nam congue, risus semper porta volutpat, quam pede lobortis ligula, sit amet eleifend pede libero quis orci. Nullam molestie nibh in lectus.\n\nPellentesque at nulla. Suspendisse potenti. Cras in purus eu magna vulputate luctus.",
"created_at": "2023-03-20T09:57:27.548697+00:00"
},
{
"id": "20",
"title": "Nam congue, risus semper porta volutpat, quam pede lobortis ligula, sit amet eleifend pede libero quis orci.",
"category": {
"id": "10",
"title": "HK"
},
"category_id": "10",
"content": "Duis aliquam convallis nunc. Proin at turpis a pede posuere nonummy. Integer non velit.\n\nDonec diam neque, vestibulum eget, vulputate ut, ultrices vel, augue. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec pharetra, magna vestibulum aliquet ultrices, erat tortor sollicitudin mi, sit amet lobortis sapien sapien non mi. Integer ac neque.\n\nDuis bibendum. Morbi non quam nec dui luctus rutrum. Nulla tellus.",
"created_at": "2023-03-20T09:57:27.548697+00:00"
}
],
"blog_posts_aggregate": {
"aggregate": {
"count": 20
}
}
}
}

View File

@@ -1,251 +0,0 @@
export const hasuraBlogPosts = {
data: {
blog_posts: [
{
id: "1",
title: "Sed ante. Vivamus tortor. Duis mattis egestas metus.",
category: {
id: "1",
title: "neque vestibulum",
},
category_id: "1",
content:
"Phasellus sit amet erat. Nulla tempus. Vivamus in felis eu sapien cursus vestibulum.",
created_at: "2023-03-20T09:57:27.548697+00:00",
},
{
id: "2",
title: "Phasellus sit amet erat.",
category: {
id: "2",
title: "enim lorem ipsum",
},
category_id: "2",
content:
"Duis bibendum, felis sed interdum venenatis, turpis enim blandit mi, in porttitor pede justo eu massa. Donec dapibus. Duis at velit eu est congue elementum.\n\nIn hac habitasse platea dictumst. Morbi vestibulum, velit id pretium iaculis, diam erat fermentum justo, nec condimentum neque sapien placerat ante. Nulla justo.\n\nAliquam quis turpis eget elit sodales scelerisque. Mauris sit amet eros. Suspendisse accumsan tortor quis turpis.",
created_at: "2023-03-20T09:57:27.548697+00:00",
},
{
id: "3",
title: "Nam ultrices, libero non mattis pulvinar, nulla pede ullamcorper augue, a suscipit nulla elit ac nulla. Sed vel enim sit amet nunc viverra dapibus.",
category: {
id: "3",
title: "vivamus vel",
},
category_id: "3",
content:
"Suspendisse potenti. In eleifend quam a odio. In hac habitasse platea dictumst.\n\nMaecenas ut massa quis augue luctus tincidunt. Nulla mollis molestie lorem. Quisque ut erat.",
created_at: "2023-03-20T09:57:27.548697+00:00",
},
{
id: "4",
title: "Suspendisse potenti. In eleifend quam a odio. In hac habitasse platea dictumst.",
category: {
id: "4",
title: "aaaaaaaaaarhoncus",
},
category_id: "4",
content:
"Proin leo odio, porttitor id, consequat in, consequat ut, nulla. Sed accumsan felis. Ut at dolor quis odio consequat varius.",
created_at: "2023-03-20T09:57:27.548697+00:00",
},
{
id: "5",
title: "In hac habitasse platea dictumst. Morbi vestibulum, velit id pretium iaculis, diam erat fermentum justo, nec condimentum neque sapien placerat ante. Nulla justo.",
category: {
id: "5",
title: "turpis adipiscing lorem",
},
category_id: "5",
content:
"Duis consequat dui nec nisi volutpat eleifend. Donec ut dolor. Morbi vel lectus in quam fringilla rhoncus.\n\nMauris enim leo, rhoncus sed, vestibulum sit amet, cursus id, turpis. Integer aliquet, massa id lobortis convallis, tortor risus dapibus augue, vel accumsan tellus nisi eu orci. Mauris lacinia sapien quis libero.\n\nNullam sit amet turpis elementum ligula vehicula consequat. Morbi a ipsum. Integer a nibh.",
created_at: "2023-03-20T09:57:27.548697+00:00",
},
{
id: "6",
title: "Maecenas rhoncus aliquam lacus. Morbi quis tortor id nulla ultrices aliquet.",
category: {
id: "6",
title: "aaaaaaaaaaaaaaaaaaaaaaaaaaaa",
},
category_id: "6",
content:
"Vestibulum quam sapien, varius ut, blandit non, interdum in, ante. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Duis faucibus accumsan odio. Curabitur convallis.\n\nDuis consequat dui nec nisi volutpat eleifend. Donec ut dolor. Morbi vel lectus in quam fringilla rhoncus.\n\nMauris enim leo, rhoncus sed, vestibulum sit amet, cursus id, turpis. Integer aliquet, massa id lobortis convallis, tortor risus dapibus augue, vel accumsan tellus nisi eu orci. Mauris lacinia sapien quis libero.",
created_at: "2023-03-20T09:57:27.548697+00:00",
},
{
id: "7",
title: "Etiam pretium iaculis justo.",
category: {
id: "7",
title: "test category",
},
category_id: "7",
content:
"In congue. Etiam justo. Etiam pretium iaculis justo.\n\nIn hac habitasse platea dictumst. Etiam faucibus cursus urna. Ut tellus.\n\nNulla ut erat id mauris vulputate elementum. Nullam varius. Nulla facilisi.",
created_at: "2023-03-20T09:57:27.548697+00:00",
},
{
id: "8",
title: "Pellentesque at nulla. Suspendisse potenti.",
category: {
id: "8",
title: "vulputate elementum nullam 2",
},
category_id: "8",
content:
"Nullam sit amet turpis elementum ligula vehicula consequat. Morbi a ipsum. Integer a nibh.",
created_at: "2023-03-20T09:57:27.548697+00:00",
},
{
id: "9",
title: "Integer ac neque. Duis bibendum. Morbi non quam nec dui luctus rutrum.",
category: {
id: "9",
title: "lacinia eget tincidunt",
},
category_id: "9",
content:
"Duis bibendum, felis sed interdum venenatis, turpis enim blandit mi, in porttitor pede justo eu massa. Donec dapibus. Duis at velit eu est congue elementum.",
created_at: "2023-03-20T09:57:27.548697+00:00",
},
{
id: "10",
title: "Aliquam non mauris. Morbi non lectus. Aliquam sit amet diam in magna bibendum imperdiet.",
category: {
id: "10",
title: "aliquam erat volutpat",
},
category_id: "10",
content:
"In hac habitasse platea dictumst. Etiam faucibus cursus urna. Ut tellus.Nulla ut erat id mauris vulputate elementum. Nullam varius. Nulla facilisi.",
created_at: "2023-03-20T09:57:27.548697+00:00",
},
{
id: "11",
title: "Praesent lectus.",
category: {
id: "1",
title: "aaaaaaaaaarhoncus",
},
category_id: "1",
content:
"Cras mi pede, malesuada in, imperdiet et, commodo vulputate, justo. In blandit ultrices enim. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.\n\nProin interdum mauris non ligula pellentesque ultrices. Phasellus id sapien in sapien iaculis congue. Vivamus metus arcu, adipiscing molestie, hendrerit at, vulputate vitae, nisl.",
created_at: "2023-03-20T09:57:27.548697+00:00",
},
{
id: "12",
title: "Nullam orci pede, venenatis non, sodales sed, tincidunt eu, felis. Fusce posuere felis sed lacus.",
category: {
id: "2",
title: "vulputate elementum nullam 2",
},
category_id: "2",
content:
"Aliquam quis turpis eget elit sodales scelerisque. Mauris sit amet eros. Suspendisse accumsan tortor quis turpis.\n\nSed ante. Vivamus tortor. Duis mattis egestas metus.\n\nAenean fermentum. Donec ut mauris eget massa tempor convallis. Nulla neque libero, convallis eget, eleifend luctus, ultricies eu, nibh.",
created_at: "2023-03-20T09:57:27.548697+00:00",
},
{
id: "13",
title: "Donec ut mauris eget massa tempor convallis. Nulla neque libero, convallis eget, eleifend luctus, ultricies eu, nibh.",
category: {
id: "3",
title: "sed accumsan felis",
},
category_id: "3",
content:
"Duis aliquam convallis nunc. Proin at turpis a pede posuere nonummy. Integer non velit.\n\nDonec diam neque, vestibulum eget, vulputate ut, ultrices vel, augue. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec pharetra, magna vestibulum aliquet ultrices, erat tortor sollicitudin mi, sit amet lobortis sapien sapien non mi. Integer ac neque.",
created_at: "2023-03-20T09:57:27.548697+00:00",
},
{
id: "14",
title: "Praesent blandit. Nam nulla. Integer pede justo, lacinia eget, tincidunt eget, tempus vel, pede.",
category: {
id: "4",
title: "enim lorem ipsum",
},
category_id: "4",
content:
"Morbi non lectus. Aliquam sit amet diam in magna bibendum imperdiet. Nullam orci pede, venenatis non, sodales sed, tincidunt eu, felis.\n\nFusce posuere felis sed lacus. Morbi sem mauris, laoreet ut, rhoncus aliquet, pulvinar sed, nisl. Nunc rhoncus dui vel sem.",
created_at: "2023-03-20T09:57:27.548697+00:00",
},
{
id: "15",
title: "In hac habitasse platea dictumst. Maecenas ut massa quis augue luctus tincidunt.",
category: {
id: "5",
title: "vulputate elementum nullam 2",
},
category_id: "5",
content:
"Pellentesque at nulla. Suspendisse potenti. Cras in purus eu magna vulputate luctus.\n\nCum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus vestibulum sagittis sapien. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.",
created_at: "2023-03-20T09:57:27.548697+00:00",
},
{
id: "16",
title: "Morbi odio odio, elementum eu, interdum eu, tincidunt in, leo.",
category: {
id: "6",
title: "blandit ultrices enim",
},
category_id: "6",
content:
"Duis bibendum, felis sed interdum venenatis, turpis enim blandit mi, in porttitor pede justo eu massa. Donec dapibus. Duis at velit eu est congue elementum.\n\nIn hac habitasse platea dictumst. Morbi vestibulum, velit id pretium iaculis, diam erat fermentum justo, nec condimentum neque sapien placerat ante. Nulla justo.",
created_at: "2023-03-20T09:57:27.548697+00:00",
},
{
id: "17",
title: "Praesent lectus.",
category: {
id: "7",
title: "amet turpis elementum",
},
category_id: "7",
content:
"In hac habitasse platea dictumst. Morbi vestibulum, velit id pretium iaculis, diam erat fermentum justo, nec condimentum neque sapien placerat ante. Nulla justo.",
created_at: "2023-03-20T09:57:27.548697+00:00",
},
{
id: "18",
title: "Proin risus. Praesent lectus.",
category: {
id: "8",
title: "ipsum primis in",
},
category_id: "8",
content:
"Etiam vel augue. Vestibulum rutrum rutrum neque. Aenean auctor gravida sem.\n\nPraesent id massa id nisl venenatis lacinia. Aenean sit amet justo. Morbi ut odio.",
created_at: "2023-03-20T09:57:27.548697+00:00",
},
{
id: "19",
title: "Integer non velit.",
category: {
id: "9",
title: "lorem integer tincidunt",
},
category_id: "9",
content:
"Fusce posuere felis sed lacus. Morbi sem mauris, laoreet ut, rhoncus aliquet, pulvinar sed, nisl. Nunc rhoncus dui vel sem.\n\nSed sagittis. Nam congue, risus semper porta volutpat, quam pede lobortis ligula, sit amet eleifend pede libero quis orci. Nullam molestie nibh in lectus.\n\nPellentesque at nulla. Suspendisse potenti. Cras in purus eu magna vulputate luctus.",
created_at: "2023-03-20T09:57:27.548697+00:00",
},
{
id: "20",
title: "Nam congue, risus semper porta volutpat, quam pede lobortis ligula, sit amet eleifend pede libero quis orci.",
category: {
id: "10",
title: "HK",
},
category_id: "10",
content:
"Duis aliquam convallis nunc. Proin at turpis a pede posuere nonummy. Integer non velit.\n\nDonec diam neque, vestibulum eget, vulputate ut, ultrices vel, augue. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec pharetra, magna vestibulum aliquet ultrices, erat tortor sollicitudin mi, sit amet lobortis sapien sapien non mi. Integer ac neque.\n\nDuis bibendum. Morbi non quam nec dui luctus rutrum. Nulla tellus.",
created_at: "2023-03-20T09:57:27.548697+00:00",
},
],
blog_posts_aggregate: {
aggregate: {
count: 20,
},
},
},
};

View File

@@ -1,61 +0,0 @@
{
"data": {
"categories": [
{
"id": "1",
"title": "aliquam erat volutpat",
"created_at": "2022-12-26T08:10:16.962584+00:00"
},
{
"id": "2",
"title": "volutpat in congue",
"created_at": "2022-12-26T08:10:16.962584+00:00"
},
{
"id": "3",
"title": "enim lorem ipsum",
"created_at": "2022-12-26T08:10:16.962584+00:00"
},
{
"id": "4",
"title": "ornare consequat lectus in",
"created_at": "2022-12-26T08:10:16.962584+00:00"
},
{
"id": "5",
"title": "vestibulum rutrum rutrum",
"created_at": "2022-12-26T08:10:16.962584+00:00"
},
{
"id": "6",
"title": "blandit ultrices enim",
"created_at": "2022-12-26T08:10:16.962584+00:00"
},
{
"id": "7",
"title": "lacinia eget tincidunt",
"created_at": "2022-12-26T08:10:16.962584+00:00"
},
{
"id": "8",
"title": "amet turpis elementum",
"created_at": "2022-12-26T08:10:16.962584+00:00"
},
{
"id": "9",
"title": "sed accumsan felis",
"created_at": "2022-12-26T08:10:16.962584+00:00"
},
{
"id": "10",
"title": "ipsum primis in",
"created_at": "2022-12-26T08:10:16.962584+00:00"
}
],
"categories_aggregate": {
"aggregate": {
"count": 10
}
}
}
}

View File

@@ -1,61 +0,0 @@
export const hasuraCategories = {
data: {
categories: [
{
id: "1",
title: "aliquam erat volutpat",
created_at: "2022-12-26T08:10:16.962584+00:00",
},
{
id: "2",
title: "volutpat in congue",
created_at: "2022-12-26T08:10:16.962584+00:00",
},
{
id: "3",
title: "enim lorem ipsum",
created_at: "2022-12-26T08:10:16.962584+00:00",
},
{
id: "4",
title: "ornare consequat lectus in",
created_at: "2022-12-26T08:10:16.962584+00:00",
},
{
id: "5",
title: "vestibulum rutrum rutrum",
created_at: "2022-12-26T08:10:16.962584+00:00",
},
{
id: "6",
title: "blandit ultrices enim",
created_at: "2022-12-26T08:10:16.962584+00:00",
},
{
id: "7",
title: "lacinia eget tincidunt",
created_at: "2022-12-26T08:10:16.962584+00:00",
},
{
id: "8",
title: "amet turpis elementum",
created_at: "2022-12-26T08:10:16.962584+00:00",
},
{
id: "9",
title: "sed accumsan felis",
created_at: "2022-12-26T08:10:16.962584+00:00",
},
{
id: "10",
title: "ipsum primis in",
created_at: "2022-12-26T08:10:16.962584+00:00",
},
],
categories_aggregate: {
aggregate: {
count: 10,
},
},
},
};

View File

@@ -1,4 +0,0 @@
{
"email": "refine",
"password": "refine"
}

View File

@@ -1,5 +0,0 @@
{
"title": "Lorem Ipsum is simply dummy text of the printing and typesetting industry",
"content": "Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.",
"status": "Published"
}

View File

@@ -1,167 +0,0 @@
[
{
"id": 1,
"title": "Ut Voluptatem Est",
"content": "Repellendus temporibus provident nobis. Non adipisci quod et est dolorem sed qui. A ut omnis. Et perspiciatis quibusdam maiores aliquid est fugit nam odit. Aut aliquam consectetur deleniti commodi velit. Eum eum aperiam voluptate quos quo. Ut quia doloribus a. Molestiae non est fugit enim fugiat non ea quas accusamus. Consequuntur voluptatem nesciunt dolorum expedita optio deserunt. Illo dolorem et similique.",
"category": {
"id": 1
},
"status": "published",
"createdAt": "2022-06-12T11:03:09.829Z",
"slug": "ut-voluptatem-est"
},
{
"id": 2,
"title": "Sequi Quod Repellendus",
"content": "Odit natus dolor consequatur tempore recusandae exercitationem. Unde dolores aut. Dolor ipsam quam quis modi sint. Dolor itaque voluptatum non qui ratione nisi ullam assumenda. Nisi et aut incidunt fuga aut deserunt. Labore sit ut quia vero vel et sed suscipit. Voluptatum maiores adipisci vel molestiae minima in enim et. Repellendus autem quis nisi vero vel consectetur laborum. Similique quos voluptates officiis velit. Sapiente nihil ut ipsa autem.",
"category": {
"id": 2
},
"status": "published",
"createdAt": "2021-10-11T08:03:00.155Z",
"slug": "sequi-quod-repellendus"
},
{
"id": 3,
"title": "Ad Enim Blanditiis",
"content": "Illo et facilis deleniti voluptatem neque et optio. Eum rerum distinctio dolor omnis sequi expedita dicta reprehenderit quaerat. In eaque odio dicta ullam cumque qui neque molestias. Libero vitae quo pariatur tempore. Excepturi fuga pariatur est sint quasi. Expedita reiciendis laboriosam explicabo ratione quia laboriosam. Alias ratione ea. Minus ut nisi ad ex eligendi id vero soluta unde. Aut aut placeat reprehenderit voluptatem ut. Voluptatibus laborum modi ducimus.",
"category": {
"id": 1
},
"status": "rejected",
"createdAt": "2022-04-16T16:34:03.319Z",
"slug": "ad-enim-blanditiis"
},
{
"id": 4,
"title": "Dolores Modi Natus",
"content": "Magnam pariatur ut ab accusamus minus labore commodi. Excepturi natus hic aut illum mollitia. Ipsum incidunt adipisci rerum veritatis quae rerum. Ipsum blanditiis quisquam ea quia et in. Exercitationem rerum in. Ut quo quia et esse expedita consequatur sint culpa voluptas. Sed optio voluptas totam id aut odio voluptatum sequi. Velit aut ea esse alias voluptatem omnis numquam aut eligendi. Voluptatem natus suscipit. Praesentium enim reiciendis nihil delectus eum totam fugit accusantium fuga.",
"category": {
"id": 2
},
"status": "published",
"createdAt": "2021-05-20T02:19:56.513Z",
"slug": "dolores-modi-natus"
},
{
"id": 5,
"title": "Repellendus Aspernatur Porro",
"content": "Blanditiis voluptas suscipit harum. Nobis aspernatur quas. Asperiores optio id iste quis sint in modi. Ea explicabo velit numquam sed natus sed aliquam. Modi sapiente expedita suscipit neque reprehenderit qui et officiis. Quis et iusto quis veniam. Ut quis quidem incidunt adipisci non et ad ut. Quis quo illum nemo. Totam esse ut quisquam dolorum explicabo. Ea mollitia sed eos ducimus saepe ratione et doloremque.",
"category": {
"id": 3
},
"status": "rejected",
"createdAt": "2022-01-09T07:01:11.195Z",
"slug": "repellendus-aspernatur-porro"
},
{
"id": 6,
"title": "Natus Ut Distinctio",
"content": "Sit ut eos nulla. Assumenda ut aut aspernatur placeat rerum numquam quasi quos. Aut nihil ratione assumenda quos voluptatem. Repudiandae excepturi vel qui vel facilis non blanditiis asperiores. Et nesciunt consequatur natus incidunt sit accusantium maxime quo. Qui modi maxime est est aut ipsam et illo nihil. Voluptas enim quod tempora sit eveniet atque. Consectetur aperiam quisquam quis rerum. Maiores repellendus dolor et earum consequuntur sit qui dolor minima. Sint vitae veritatis qui consequuntur nemo impedit et.",
"category": {
"id": 4
},
"status": "published",
"createdAt": "2023-02-01T15:32:15.719Z",
"slug": "natus-ut-distinctio"
},
{
"id": 7,
"title": "Vel Labore Sint",
"content": "Quasi magni asperiores laborum accusantium debitis in voluptas quia. Velit mollitia earum magnam maxime aut. Enim at assumenda quidem vel libero facilis vel. Enim voluptate maiores. Quia ut odio fugit tempore iste qui et. Sit eaque voluptate omnis dolorem perspiciatis deleniti non qui assumenda. Possimus et rerum nam possimus inventore dolorem corrupti earum. Architecto consequuntur et cupiditate. Molestiae nisi facere qui ut saepe quis. Eius adipisci tempore itaque sed odio veniam harum quia.",
"category": {
"id": 5
},
"status": "rejected",
"createdAt": "2022-02-27T09:01:32.679Z",
"slug": "vel-labore-sint"
},
{
"id": 8,
"title": "Minus Nulla Molestias",
"content": "Qui velit dolorem fuga ad quas omnis harum. Ipsam sint ipsam quos nam sed adipisci. Aut adipisci asperiores tenetur laborum accusantium sint atque. Optio delectus fugiat iusto ut consequatur non delectus sit. Aut corrupti est sequi rerum asperiores fuga aut velit laborum. Quaerat magnam fuga dolores. Vel tenetur neque sapiente. Soluta quia autem delectus eos eveniet. Qui quis et velit molestiae enim qui explicabo dolor. Sit placeat molestias fugiat optio repellat voluptas.",
"category": {
"id": 6
},
"status": "rejected",
"createdAt": "2022-11-07T12:30:27.331Z",
"slug": "minus-nulla-molestias"
},
{
"id": 9,
"title": "Quibusdam Ut Natus",
"content": "Minus nam fugiat veritatis sequi ut. Iure nisi hic exercitationem rerum tempore earum. Rerum velit nemo est omnis nulla consequatur excepturi aut. Iusto ut autem porro commodi non. Et excepturi et aliquid alias qui minima nostrum deleniti. Ut qui consequatur voluptatem. Recusandae eos et odit neque. Non quaerat voluptatem molestiae necessitatibus. Et omnis dolore aperiam delectus. Rerum et et libero.",
"category": {
"id": 7
},
"status": "draft",
"createdAt": "2021-12-18T05:22:45.857Z",
"slug": "quibusdam-ut-natus"
},
{
"id": 10,
"title": "Nam Voluptas Ipsum",
"content": "Eum quaerat nostrum nulla consequatur quia quod autem minus. Quis omnis corrupti qui dolores. Non soluta suscipit. Ut distinctio eius consequuntur unde ab vel nobis sint nostrum. Natus omnis omnis debitis. Porro sit rerum vitae officiis dolorem veniam occaecati amet. Vitae et facilis provident enim et perferendis dolorum voluptatum. Fugiat provident explicabo ut libero aperiam dolore voluptatem. Et reiciendis error cupiditate blanditiis ea velit in incidunt. Doloribus et quis totam.",
"category": {
"id": 8
},
"status": "rejected",
"createdAt": "2021-11-21T05:29:05.942Z",
"slug": "nam-voluptas-ipsum"
},
{
"id": 11,
"title": "Nam Placeat Expedita",
"content": "Et iusto vel aut animi mollitia. Nesciunt nobis sunt et dolore soluta. Dolore doloremque qui vero ut. Aperiam maiores ea. Consequuntur omnis eos. Ipsam reprehenderit cupiditate maiores est fuga dolorum repellendus quisquam dolorem. Consequatur ea reprehenderit nulla quia occaecati laboriosam. Maiores dicta in tempora. Tempora et adipisci aspernatur est. Ipsum et molestiae illum fugiat.",
"category": {
"id": 9
},
"status": "rejected",
"createdAt": "2023-05-05T19:52:59.535Z",
"slug": "nam-placeat-expedita"
},
{
"id": 12,
"title": "Rerum Voluptatem Sunt",
"content": "Voluptas et cumque numquam. Suscipit eum cumque cupiditate vel possimus voluptatibus est ut. Optio molestiae nisi officiis sint sed vel provident accusantium. Omnis voluptatum officiis voluptatem numquam necessitatibus quisquam. A sit quae numquam numquam est. Aut in placeat. Modi quod et quaerat autem nemo. Amet in laudantium. Quis adipisci facere. Sed suscipit labore.",
"category": {
"id": 4
},
"status": "rejected",
"createdAt": "2021-06-26T00:07:45.503Z",
"slug": "rerum-voluptatem-sunt"
},
{
"id": 13,
"title": "In Sequi Recusandae",
"content": "Quia sit nulla occaecati enim. Totam rerum delectus. Quidem dolorum a rerum odio. Et molestias magnam amet sint soluta nemo. Dolore incidunt voluptatum quo recusandae quis consectetur est rerum nobis. Sit facere dignissimos libero et sint unde nam atque sunt. Tenetur facilis eos animi animi possimus. Qui maxime ut eum. Quas accusantium non rerum accusantium id soluta. Illum fugiat similique cumque.",
"category": {
"id": 2
},
"status": "draft",
"createdAt": "2021-10-02T13:20:44.138Z",
"slug": "in-sequi-recusandae"
},
{
"id": 14,
"title": "Impedit Maiores Consequatur",
"content": "Quibusdam sed incidunt assumenda. Nulla unde optio. Reiciendis placeat provident aut culpa aut nam et quis dolores. Ipsa velit non enim est earum quae velit totam corporis. Quod unde recusandae. Dolores et sed vel illo perferendis vitae sunt et. Cumque voluptatem dolores aut illum. Qui voluptates id ut est maxime adipisci rerum. Enim porro quo repudiandae dolore enim incidunt iste. Perferendis adipisci dicta harum.",
"category": {
"id": 3
},
"status": "draft",
"createdAt": "2021-06-06T15:12:04.543Z",
"slug": "impedit-maiores-consequatur"
},
{
"id": 15,
"title": "Deserunt Ut Enim",
"content": "Explicabo quaerat officia rerum nobis non sint. Fugit blanditiis ipsum et tempora iure eaque quo. Ratione sed voluptatem rerum ad illum veniam sint. Excepturi aliquam et. Dolor reprehenderit reiciendis quia voluptatem accusamus odio et et. Voluptatem maxime enim reprehenderit veritatis voluptatem maxime. Non quia adipisci molestiae dolorem voluptatum ipsam libero sed. Illo et voluptatem. Atque sit eos et fugit fugiat quia sed aliquam eveniet. Veniam nulla dolorem exercitationem blanditiis consequatur ipsam.",
"category": {
"id": 9
},
"status": "draft",
"createdAt": "2022-04-24T18:07:20.293Z",
"slug": "deserunt-ut-enim"
}
]

View File

@@ -1,4 +0,0 @@
{
"email": "demo@refine.dev",
"password": "demodemo"
}

View File

@@ -1,4 +0,0 @@
{
"email": "info@refine.dev",
"password": "refine-supabase"
}

View File

@@ -1,81 +0,0 @@
/// <reference types="cypress" />
/// <reference types="../../index.d.ts" />
export const getAntdNotification = () => {
return cy.get(".ant-notification-notice");
};
export const setAntdDropdown = ({
id,
selectIndex,
}: ISetAntdDropdownParams) => {
return cy
.get(`#${id}`)
.click({ force: true })
.get(".ant-select-item-option")
.eq(selectIndex || 0)
.click({ force: true })
.get(`#${id}`)
.blur();
};
export const setAntdSelect = ({ id, value }: ISetAntdSelectParams) => {
return cy
.get(`#${id}`)
.click({ force: true })
.get(`.ant-select-item[title="${value}"]`)
.click({ force: true })
.get(`#${id}`)
.blur();
};
export const setAntdRangeDatePickerToToday = ({
id,
}: ISetAntdRangeDatePickerToTodayParams) => {
return cy
.get(`#${id}`)
.click({ force: true })
.get(".ant-picker-cell-today")
.eq(0)
.click({ force: true })
.click({ force: true });
};
export const getAntdFormItemError = ({ id }: IGetAntdFormItemErrorParams) => {
return cy.get(`#${id}_help > .ant-form-item-explain-error`);
};
export const getAntdLoadingOverlay = () => {
return cy.get(`.ant-spin`);
};
export const getAntdPopoverDeleteButton = () => {
return cy.get(".ant-popconfirm-buttons button").contains(/delete/gi);
};
export const getAntdColumnSorter = (index: number) => {
return cy.get(".ant-table-column-sorters").eq(index);
};
export const getAntdFilterTrigger = (index: number) => {
return cy.get(".ant-table-filter-trigger").eq(index);
};
export const getAntdPaginationItem = (index: number) => {
return cy.get(`.ant-pagination-item-${index}`);
};
export const getTableRowExpandButton = (index: number) => {
return cy.get(".ant-table-row-expand-icon").eq(index);
};
export const fillAntdForm = () => {
cy.fixture("mock-post").then((mockPost) => {
cy.get("#title").clear();
cy.get("#title").type(mockPost.title);
cy.get("#content textarea").clear();
cy.get("#content textarea").type(mockPost.content);
cy.setAntdDropdown({ id: "category_id", selectIndex: 0 });
cy.setAntdSelect({ id: "status", value: mockPost.status });
});
};

View File

@@ -1,44 +0,0 @@
export const getChakraUINotification = () => {
return cy.get(".chakra-alert");
};
export const getChakraUIToast = () => {
return cy.get(".chakra-toast");
};
export const getChakraUIFormItemError = ({
id,
type = "text",
}: IGetChakraUIFormItemErrorParams) => {
if (type === "text") {
return cy.get(`#${id}`).siblings(".chakra-form__error-message");
}
if (type === "select") {
return cy
.get(`#${id}`)
.parent()
.parent()
.find(".chakra-form__error-message");
}
// type === "text"
return cy.get(`#${id}`).siblings(".chakra-form__error-message");
};
export const getChakraUIPopoverDeleteButton = () => {
return cy.get(".chakra-popover__body button").contains(/delete/gi);
};
export const getChakraUILoadingOverlay = () => {
return cy.get(".chakra-spinner");
};
export const fillChakraUIForm = () => {
cy.fixture("mock-post").then((mockPost) => {
cy.get("#title").clear().type(mockPost.title);
cy.get("#status").select(mockPost.status.toLowerCase());
cy.get("#categoryId").select(2);
cy.get("#content").clear().type(mockPost.content);
});
};

View File

@@ -1,47 +0,0 @@
/// <reference types="cypress" />
/// <reference types="../index.d.ts" />
export const assertDocumentTitle = (resource: string, action?: IAction) => {
switch (action) {
case "list":
cy.document()
.its("title")
.should("match", new RegExp(`^${resource} | refine$`, "i"));
break;
case "edit":
cy.document()
.its("title")
.should(
"match",
new RegExp(`^#\\d+ Edit ${resource} | refine$`, "i"),
);
break;
case "show":
cy.document()
.its("title")
.should(
"match",
new RegExp(`^#\\d+ Show ${resource} | refine$`, "i"),
);
break;
case "create":
cy.document()
.its("title")
.should(
"match",
new RegExp(`^Create new ${resource} | refine$`, "i"),
);
break;
case "clone":
cy.document()
.its("title")
.should(
"match",
new RegExp(`^#\\d+ Clone ${resource} | refine$`, "i"),
);
break;
default:
cy.document().its("title").should("eq", `refine`);
break;
}
};

View File

@@ -1,252 +0,0 @@
/// <reference types="cypress" />
/// <reference types="../../index.d.ts" />
import { getIdFromURL } from "../../../utils";
const hostname = "api.fake-rest.refine.dev";
Cypress.Commands.add("interceptGETPosts", () => {
return cy
.intercept(
{
method: "GET",
hostname: hostname,
pathname: "/posts",
},
{
fixture: "posts.json",
},
)
.as("getPosts");
});
Cypress.Commands.add("interceptGETPost", () => {
return cy
.fixture("posts")
.then((posts) => {
return cy.intercept(
{
method: "GET",
hostname: hostname,
pathname: "/posts/*",
},
(req) => {
const id = getIdFromURL(req.url);
const post = posts.find((post) => post.id === id);
if (!post) {
req.reply(404, {});
return;
}
req.reply(post);
},
);
})
.as("getPost");
});
Cypress.Commands.add("interceptPOSTPost", () => {
return cy.fixture("posts").then((posts) =>
cy
.intercept(
{
method: "POST",
hostname: hostname,
pathname: "/posts",
},
(req) => {
const merged = Object.assign({}, req.body, {
id: posts.length + 1,
});
return req.reply(merged);
},
)
.as("postPost"),
);
});
Cypress.Commands.add("interceptPATCHPost", () => {
return cy
.fixture("posts")
.then((posts) => {
return cy.intercept(
{
method: "PATCH",
hostname: hostname,
pathname: "/posts/*",
},
(req) => {
const id = getIdFromURL(req.url);
const post = posts.find((post) => post.id === id);
if (!post) {
return req.reply(404, {});
}
const merged = Object.assign({}, post, req.body);
return req.reply(merged);
},
);
})
.as("patchPost");
});
Cypress.Commands.add("interceptDELETEPost", () => {
return cy
.intercept(
{
method: "DELETE",
hostname: hostname,
pathname: "/posts/*",
},
{},
)
.as("deletePost");
});
Cypress.Commands.add("interceptGETCategories", () => {
return cy
.intercept(
{
method: "GET",
hostname: hostname,
pathname: "/categories",
},
{ fixture: "categories.json" },
)
.as("getCategories");
});
Cypress.Commands.add("interceptGETCategory", () => {
return cy
.fixture("categories")
.then((categories) => {
return cy.intercept(
{
method: "GET",
hostname: hostname,
pathname: "/categories/*",
},
(req) => {
const id = getIdFromURL(req.url);
const category = categories.find(
(category) => category.id.toString() === id.toString(),
);
if (!category) {
req.reply(404, {});
return;
}
req.reply(category);
},
);
})
.as("getCategory");
});
Cypress.Commands.add("interceptGETBlogPosts", () => {
return cy
.intercept(
{
method: "GET",
hostname: hostname,
pathname: "/blog_posts",
},
{
fixture: "blog-posts.json",
},
)
.as("getBlogPosts");
});
Cypress.Commands.add("interceptGETBlogPost", () => {
return cy
.fixture("blog-posts")
.then((posts) => {
return cy.intercept(
{
method: "GET",
hostname: hostname,
pathname: "/blog_posts/*",
},
(req) => {
const id = getIdFromURL(req.url);
const post = posts.find((post) => post.id === id);
if (!post) {
req.reply(404, {});
return;
}
req.reply(post);
},
);
})
.as("getBlogPost");
});
Cypress.Commands.add("interceptPOSTBlogPost", () => {
return cy.fixture("blog-posts").then((posts) =>
cy
.intercept(
{
method: "POST",
hostname: hostname,
pathname: "/blog_posts",
},
(req) => {
const merged = Object.assign({}, req.body, {
id: posts.length + 1,
});
return req.reply(merged);
},
)
.as("postBlogPost"),
);
});
Cypress.Commands.add("interceptPATCHBlogPost", () => {
return cy
.fixture("blog-posts")
.then((posts) => {
return cy.intercept(
{
method: "PATCH",
hostname: hostname,
pathname: "/blog_posts/*",
},
(req) => {
const id = getIdFromURL(req.url);
const post = posts.find((post) => post.id === id);
if (!post) {
return req.reply(404, {});
}
const merged = Object.assign({}, post, req.body);
return req.reply(merged);
},
);
})
.as("patchBlogPost");
});
Cypress.Commands.add("interceptDELETEBlogPost", () => {
return cy
.intercept(
{
method: "DELETE",
hostname: hostname,
pathname: "/blog_posts/*",
},
{},
)
.as("deleteBlogPost");
});

View File

@@ -1,151 +0,0 @@
import { CyHttpMessages } from "cypress/types/net-stubbing";
import hasuraBlogPosts from "../../../fixtures/hasura-blog-posts.json";
import hasuraCategories from "../../../fixtures/hasura-categories.json";
type Operation = "get" | "getAll" | "create" | "update" | "delete";
export const getOperation = (
req: CyHttpMessages.IncomingHttpRequest,
): Operation | null => {
const query = req.body.query as string;
if (query.startsWith("query")) {
if (query.includes("aggregate") || query.includes("$where")) {
return "getAll";
}
if (query.includes("by_pk")) {
return "get";
}
}
if (query.startsWith("mutation")) {
if (query.includes("delete")) {
return "delete";
}
if (query.includes("$_set")) {
return "update";
}
if (query.includes("insert")) {
return "create";
}
}
return null;
};
const getResource = (req: CyHttpMessages.IncomingHttpRequest) => {
const query = req.body.query as string;
if (query.includes("blog_posts")) {
return "BlogPosts";
}
if (query.includes("categories")) {
return "Categories";
}
return null;
};
Cypress.Commands.add("interceptHasura", () => {
return cy.intercept(
{
method: "POST",
hostname: "flowing-mammal-24.hasura.app",
pathname: "/v1/graphql",
},
(req) => {
const body = req.body;
const operation = getOperation(req);
const resource = getResource(req);
const alias = `${operation}${resource}`;
console.log({ alias, body });
if (!operation || !resource) {
console.log("no operation or resource", {
operation,
resource,
});
return req.reply(404, {});
}
req.alias = alias;
if (resource === "BlogPosts") {
if (operation === "getAll") {
return req.reply({
data: hasuraBlogPosts.data,
});
}
if (operation === "get") {
const id = body.variables.id;
const { category: _category, ...post } =
hasuraBlogPosts.data.blog_posts.find(
(post) => post.id === id,
) as any;
if (!post) {
return req.reply(404, {});
}
return req.reply({
data: {
blog_posts_by_pk: post,
},
});
}
if (operation === "update") {
return req.reply({
data: {
update_blog_posts_by_pk: body.variables._set,
},
});
}
if (operation === "delete") {
return req.reply({
data: {
delete_blog_posts_by_pk: {
id: body.variables.id,
},
},
});
}
}
if (resource === "Categories") {
if (operation === "getAll") {
return req.reply({
data: hasuraCategories.data,
});
}
if (operation === "get") {
const id = body.variables.id;
const category = hasuraCategories.data.categories.find(
(category) => category.id === id,
);
if (!category) {
console.log("no category found", {
id,
category,
});
return req.reply(404, {});
}
return req.reply({
data: {
categories_by_pk: category,
},
});
}
}
},
);
});

View File

@@ -1,5 +0,0 @@
// add commands to the Cypress chain
import "./api-fake-rest";
import "./supabase";
import "./strapi-v4";
import "./hasura";

View File

@@ -1,158 +0,0 @@
/// <reference types="cypress" />
/// <reference types="../../index.d.ts" />
import { getIdFromURL } from "../../../utils";
const hostname = "api.strapi-v4.refine.dev";
const BASE_PATH = "/api";
Cypress.Commands.add("interceptStrapiV4GETPosts", () => {
return cy
.intercept(
{
method: "GET",
hostname: hostname,
pathname: `${BASE_PATH}/posts`,
},
{
fixture: "posts.json",
},
)
.as("strapiV4GetPosts");
});
Cypress.Commands.add("interceptStrapiV4GETPost", () => {
return cy
.fixture("posts")
.then((posts) => {
return cy.intercept(
{
method: "GET",
hostname: hostname,
pathname: `${BASE_PATH}/posts/*`,
},
(req) => {
const id = getIdFromURL(req.url);
const post = posts.find(
(post) => post.id.toString() === id.toString(),
);
if (!post) {
req.reply(404, {});
return;
}
req.reply({
data: post,
meta: {},
});
},
);
})
.as("strapiV4GetPost");
});
Cypress.Commands.add("interceptStrapiV4POSTPost", () => {
return cy.fixture("posts").then((posts) =>
cy
.intercept(
{
method: "POST",
hostname: hostname,
pathname: `${BASE_PATH}/posts`,
},
(req) => {
const merged = Object.assign({}, req.body, {
id: posts.length + 1,
});
return req.reply(merged);
},
)
.as("strapiV4PostPost"),
);
});
Cypress.Commands.add("interceptStrapiV4PUTPost", () => {
return cy
.fixture("posts")
.then((posts) => {
return cy.intercept(
{
method: "PUT",
hostname: hostname,
pathname: `${BASE_PATH}/posts/*`,
},
(req) => {
const id = getIdFromURL(req.url);
const post = posts.find((post) => post.id === id);
if (!post) {
return req.reply(404, {});
}
const merged = Object.assign({}, post, req.body);
return req.reply(merged);
},
);
})
.as("strapiV4PutPost");
});
Cypress.Commands.add("interceptStrapiV4DELETEPost", () => {
return cy
.intercept(
{
method: "DELETE",
hostname: hostname,
pathname: `${BASE_PATH}/posts/*`,
},
{},
)
.as("strapiV4DeletePost");
});
Cypress.Commands.add("interceptStrapiV4GETCategories", () => {
return cy
.intercept(
{
method: "GET",
hostname: hostname,
pathname: `${BASE_PATH}/categories`,
},
{ fixture: "categories.json" },
)
.as("strapiV4GetCategories");
});
Cypress.Commands.add("interceptStrapiV4GETCategory", () => {
return cy
.fixture("categories")
.then((categories) => {
return cy.intercept(
{
method: "GET",
hostname: hostname,
pathname: `${BASE_PATH}/categories/*`,
},
(req) => {
const id = getIdFromURL(req.url);
const category = categories.find(
(category) => category.id.toString() === id.toString(),
);
if (!category) {
req.reply(404, {});
return;
}
req.reply({
data: category,
});
},
);
})
.as("strapiV4GetCategory");
});

View File

@@ -1,138 +0,0 @@
/// <reference types="cypress" />
/// <reference types="../../index.d.ts" />
import { ICategory, IPost } from "../../types";
const HOSTNAME = "iwdfzvfqbtokqetmbmbp.supabase.co";
const BASE_PATH = "/rest/v1";
const getSupabaseIdFromQuery = (query?: Record<string, string | number>) => {
// supabase uses id in query like this {id: 'eq.1'}
return (query?.id as string)?.split(".")?.[1];
};
Cypress.Commands.add("interceptSupabaseGETPosts", () => {
// read posts and categories from fixtures
let posts: (IPost & {
categories: ICategory;
})[] = [];
let categories: ICategory[] = [];
cy.fixture("categories").then((categoriesFixture) => {
categories = categoriesFixture;
});
// transform fixtures to match supabase response
cy.fixture("posts").then((rawPosts) => {
posts = rawPosts.map((post) => {
// in supabase, the category is not object, but in fixture it is
// because of that, we need to convert it to categoryId
return Object.assign({}, post, {
categoryId: post.category.id,
categories: categories.find(
(category) => category.id === post.category.id,
),
});
});
});
return cy
.intercept(
{
method: "GET",
hostname: HOSTNAME,
pathname: `${BASE_PATH}/posts`,
},
(req) => {
const id = getSupabaseIdFromQuery(req.query);
if (id) {
const post = posts.find(
(post) => post.id.toString() === id.toString(),
);
if (!post) {
return req.reply(404, []);
}
return req.reply([post]);
}
return req.reply(posts);
},
)
.as("supabaseGetPosts");
});
Cypress.Commands.add("interceptSupabasePOSTPost", () => {
return cy.fixture("posts").then((posts) =>
cy
.intercept(
{
method: "POST",
hostname: HOSTNAME,
pathname: `${BASE_PATH}/posts`,
},
(req) => {
const merged = Object.assign({}, req.body, {
id: posts.length + 1,
});
return req.reply(merged);
},
)
.as("supabasePostPost"),
);
});
Cypress.Commands.add("interceptSupabasePATCHPost", () => {
return cy
.fixture("posts")
.then((posts) => {
return cy.intercept(
{
method: "PATCH",
hostname: HOSTNAME,
pathname: `${BASE_PATH}/posts`,
},
(req) => {
const id = getSupabaseIdFromQuery(req.query);
const post = posts.find(
(post) => post.id.toString() === id.toString(),
);
if (!post) {
return req.reply(404, {});
}
const merged = Object.assign({}, post, req.body);
return req.reply(merged);
},
);
})
.as("supabasePatchPost");
});
Cypress.Commands.add("interceptSupabaseDELETEPost", () => {
return cy
.intercept(
{
method: "DELETE",
hostname: HOSTNAME,
pathname: `${BASE_PATH}/posts`,
},
{},
)
.as("supabaseDeletePost");
});
Cypress.Commands.add("interceptSupabaseGETCategories", () => {
return cy
.intercept(
{
method: "GET",
hostname: HOSTNAME,
pathname: `${BASE_PATH}/categories*`,
},
{ fixture: "categories.json" },
)
.as("supabaseGetCategories");
});

View File

@@ -1,30 +0,0 @@
export const getMantineNotification = () => {
return cy.get(".mantine-Notification-description");
};
export const getMantinePopoverDeleteButton = () => {
return cy.get(".mantine-Popover-dropdown").contains(/delete/gi);
};
export const getMantineFormItemError = ({
id,
}: IGetChakraUIFormItemErrorParams) => {
return cy.get(`#${id}-error`);
};
export const getMantineLoadingOverlay = () => {
return cy.get(".mantine-LoadingOverlay-root");
};
export const fillMantineForm = () => {
cy.fixture("mock-post").then((mockPost) => {
cy.get("#title").clear().type(mockPost.title);
cy.get("#content textarea")
.clear({ force: true })
.type(mockPost.content, {
delay: 32,
});
cy.get("#status").click().get("#status-0").click();
cy.get("#categoryId").clear().get("#categoryId-1").click();
});
};

View File

@@ -1,37 +0,0 @@
/// <reference types="cypress" />
/// <reference types="../../index.d.ts" />
export const getMaterialUINotifications = () => {
return cy.get("#notistack-snackbar .MuiBox-root > h6");
};
export const getMaterialUIDeletePopoverButton = () => {
return cy.get(".MuiDialogActions-root > button").contains(/delete/i);
};
export const getMaterialUIFormItemError = ({
id,
}: IGetMaterialUIFormItemErrorParams) => {
return cy.get(`#${id}-helper-text`);
};
export const getMaterialUILoadingCircular = () => {
return cy.get(".MuiCircularProgress-root");
};
export const getMaterialUIColumnHeader = (index: number) => {
return cy.get(`.MuiDataGrid-columnHeader[aria-colindex="${index}"]`);
};
export const fillMaterialUIForm = () => {
cy.fixture("mock-post").then((mockPost) => {
cy.get("#title").clear();
cy.get("#title").type(mockPost.title);
cy.get("#content").clear();
cy.get("#content").type(mockPost.content);
cy.get("#status").click();
cy.get("#status-option-0").click();
cy.get("#category").click();
cy.get("#category-option-0").click();
});
};

View File

@@ -1,23 +0,0 @@
export const getSaveButton = () => {
return cy.get(".refine-save-button");
};
export const getCreateButton = () => {
return cy.get(".refine-create-button");
};
export const getDeleteButton = () => {
return cy.get(".refine-delete-button");
};
export const getEditButton = () => {
return cy.get(".refine-edit-button");
};
export const getShowButton = () => {
return cy.get(".refine-show-button");
};
export const getPageHeaderTitle = () => {
return cy.get(".refine-pageHeader-title");
};

View File

@@ -1,265 +0,0 @@
/// <reference types="cypress" />
/// <reference types="../index.d.ts" />
const assertNotification = (ui: UITypes) => {
switch (ui) {
case "antd":
return cy.getAntdNotification().should("contain", "Success");
case "chakra-ui":
return cy.getChakraUINotification().should("contain", "Success");
case "mantine":
return cy.getMantineNotification().should("contain", "Success");
case "material-ui":
return cy.getMaterialUINotification().should("contain", "Success");
}
};
const waitLoadingOverlay = (ui: UITypes) => {
switch (ui) {
case "antd":
return cy.getAntdLoadingOverlay().should("not.exist");
case "chakra-ui":
return cy.getChakraUILoadingOverlay().should("not.exist");
case "mantine":
return cy.getMantineLoadingOverlay().should("not.exist");
case "material-ui":
return cy.getMaterialUILoadingCircular().should("not.exist");
}
};
const fillForm = (ui: UITypes) => {
switch (ui) {
case "antd":
return cy.fillAntdForm();
case "chakra-ui":
return cy.fillChakraUIForm();
case "mantine":
return cy.fillMantineForm();
case "material-ui":
return cy.fillMaterialUIForm();
}
};
const assertFormShouldHaveResponseValues = (response: any, ui: UITypes) => {
const body = response?.body;
// assert response values are equal to the form values
switch (ui) {
case "antd":
cy.get("#title").should("have.value", body?.title);
cy.get("#content textarea").should("have.value", body?.content);
cy.get("#status")
.parent()
.siblings()
.last()
.should(($status) => {
return (
$status.val()?.toString().toLowerCase() ===
body?.status.toLowerCase()
);
});
cy.get("#category_id")
.parent()
.siblings()
.last()
.should(($category_id) => {
return (
$category_id.val()?.toString().toLowerCase() ===
body?.status.toLowerCase()
);
});
break;
case "chakra-ui":
cy.get("#title").should("have.value", body?.title);
cy.get("#status").should("have.value", body?.status);
cy.get("#content").should("have.value", body?.content);
cy.get("#categoryId").should("have.value", body?.category?.id);
break;
case "mantine":
cy.get("#title").should("have.value", body?.title);
cy.get("#content textarea").should("have.value", body?.content);
cy.get("#status").should(($status) => {
return (
$status.val()?.toString().toLowerCase() ===
body?.status.toLowerCase()
);
});
cy.fixture("categories").then((categories) => {
const category = categories.find(
(category) => category.id === body?.category?.id,
);
cy.get("#categoryId").should("have.value", category?.title);
});
break;
case "material-ui":
cy.get("#title").should("have.value", body?.title);
cy.get("#content").should("have.value", body?.content);
cy.get("#status").should("have.value", body?.status);
cy.fixture("categories").then((categories) => {
const category = categories.find(
(category) => category.id === body?.category?.id,
);
cy.get("#category").should("have.value", category?.title);
});
break;
}
};
const assertSuccessResponse = (response: any, ui: UITypes) => {
const body = response?.body;
expect(response?.statusCode).to.eq(200);
expect(body).to.have.property("id");
expect(body).to.have.property("category");
cy.fixture("mock-post").then((mockPost) => {
expect(body?.title).to.eq(mockPost.title);
expect(body?.content).to.eq(mockPost.content);
expect(body?.status?.toLowerCase()).to.eq(
mockPost?.status?.toLowerCase(),
);
});
assertNotification(ui);
cy.location().should((loc) => {
expect(loc.pathname).to.eq("/posts");
});
};
export const list = () => {
cy.url().should("include", "/posts");
cy.getPageHeaderTitle().should("contain", "Posts");
cy.assertDocumentTitle("Posts", "list");
};
export const create = ({ ui }: IResourceCreateParams) => {
cy.interceptGETCategories();
cy.getCreateButton().click();
cy.wait("@getCategories");
cy.location("pathname").should("eq", "/posts/create");
cy.assertDocumentTitle("Post", "create");
fillForm(ui);
cy.interceptPOSTPost();
cy.getSaveButton().click();
cy.wait("@postPost").then((interception) => {
const response = interception?.response;
assertSuccessResponse(response, ui);
});
};
export const edit = ({ ui }: IResourceEditParams) => {
cy.interceptGETCategories();
cy.interceptGETPost();
// wait loading state and render to be finished
cy.wait("@getPosts");
waitLoadingOverlay(ui);
cy.getEditButton().first().click();
cy.wait("@getCategories");
cy.wait("@getPost").then((interception) => {
const getResponse = interception?.response;
// wait loading state and render to be finished
waitLoadingOverlay(ui);
cy.getSaveButton().should("not.be.disabled");
cy.location("pathname").should("include", "/posts/edit");
assertFormShouldHaveResponseValues(getResponse, ui);
});
cy.assertDocumentTitle("Post", "edit");
fillForm(ui);
cy.interceptPATCHPost();
cy.getSaveButton().click();
cy.wait("@patchPost").then((interception) => {
const response = interception?.response;
assertSuccessResponse(response, ui);
});
};
export const show = () => {
cy.interceptGETPost();
cy.interceptGETCategory();
cy.getShowButton().first().click();
cy.assertDocumentTitle("Post", "show");
cy.wait("@getPost").then((interception) => {
const response = interception?.response;
const id = response?.body?.id;
cy.location("pathname").should("include", `/posts/show/${id}`);
// should be visible id,title,content
["Id", "Title", "Content"].forEach((field) => {
cy.get("body").should("contain", field);
});
// should be visible id,title,content values
const title = response?.body?.title;
const content = response?.body?.content;
[id, title, content].forEach((value) => {
cy.get("body").should("contain", value);
});
});
cy.wait("@getCategory").then((interception) => {
const response = interception?.response;
const category = response?.body;
cy.get("body").should("contain", category?.title);
});
};
export const resourceDelete = ({ ui }: IResourceDeleteParams) => {
cy.interceptGETCategories();
cy.wait("@getPosts");
waitLoadingOverlay(ui);
cy.interceptGETPost();
cy.getEditButton().first().click();
// wait loading state and render to be finished
cy.wait("@getPost");
waitLoadingOverlay(ui);
cy.getSaveButton().should("not.be.disabled");
cy.interceptDELETEPost();
cy.getDeleteButton().first().click();
switch (ui) {
case "antd":
cy.getAntdPopoverDeleteButton().click({ force: true });
break;
case "chakra-ui":
cy.getChakraUIPopoverDeleteButton().click({ force: true });
break;
case "mantine":
cy.getMantinePopoverDeleteButton().click({ force: true });
break;
case "material-ui":
cy.getMaterialUIDeletePopoverButton().click({ force: true });
break;
}
cy.wait("@deletePost").then((interception) => {
const response = interception?.response;
expect(response?.statusCode).to.eq(200);
assertNotification(ui);
cy.location().should((loc) => {
expect(loc.pathname).to.eq("/posts");
});
});
};

View File

@@ -1,133 +0,0 @@
/// <reference types="cypress" />
/// <reference types="./index.d.ts" />
import {
getAntdNotification,
setAntdSelect,
setAntdDropdown,
getAntdFormItemError,
getAntdLoadingOverlay,
getAntdPopoverDeleteButton,
getAntdColumnSorter,
getAntdFilterTrigger,
getAntdPaginationItem,
getTableRowExpandButton,
setAntdRangeDatePickerToToday,
fillAntdForm,
} from "./commands/antd";
import {
getChakraUIPopoverDeleteButton,
getChakraUIFormItemError,
getChakraUILoadingOverlay,
getChakraUINotification,
getChakraUIToast,
fillChakraUIForm,
} from "./commands/chakra-ui";
import {
fillMantineForm,
getMantineFormItemError,
getMantineLoadingOverlay,
getMantineNotification,
getMantinePopoverDeleteButton,
} from "./commands/mantine";
import {
getCreateButton,
getDeleteButton,
getEditButton,
getPageHeaderTitle,
getSaveButton,
getShowButton,
} from "./commands/refine";
import { list, create, edit, show, resourceDelete } from "./commands/resource";
import { assertDocumentTitle } from "./commands/document-title-handler";
// add commands to the Cypress chain
import "./commands/intercepts";
import {
fillMaterialUIForm,
getMaterialUIColumnHeader,
getMaterialUIDeletePopoverButton,
getMaterialUIFormItemError,
getMaterialUILoadingCircular,
getMaterialUINotifications,
} from "./commands/material-ui";
Cypress.Keyboard.defaults({
keystrokeDelay: 0,
});
Cypress.config("defaultCommandTimeout", 20000);
Cypress.config("requestTimeout", 20000);
Cypress.Commands.add("assertDocumentTitle", assertDocumentTitle);
Cypress.Commands.add("resourceList", list);
Cypress.Commands.add("resourceCreate", create);
Cypress.Commands.add("resourceEdit", edit);
Cypress.Commands.add("resourceShow", show);
Cypress.Commands.add("resourceDelete", resourceDelete);
Cypress.Commands.add("getSaveButton", getSaveButton);
Cypress.Commands.add("getCreateButton", getCreateButton);
Cypress.Commands.add("getDeleteButton", getDeleteButton);
Cypress.Commands.add("getEditButton", getEditButton);
Cypress.Commands.add("getShowButton", getShowButton);
Cypress.Commands.add("getPageHeaderTitle", getPageHeaderTitle);
Cypress.Commands.add("fillAntdForm", fillAntdForm);
Cypress.Commands.add("getAntdNotification", getAntdNotification);
Cypress.Commands.add("setAntdSelect", setAntdSelect);
Cypress.Commands.add("setAntdDropdown", setAntdDropdown);
Cypress.Commands.add("getAntdFormItemError", getAntdFormItemError);
Cypress.Commands.add("getAntdLoadingOverlay", getAntdLoadingOverlay);
Cypress.Commands.add("getAntdPopoverDeleteButton", getAntdPopoverDeleteButton);
Cypress.Commands.add("getAntdColumnSorter", getAntdColumnSorter);
Cypress.Commands.add("getAntdFilterTrigger", getAntdFilterTrigger);
Cypress.Commands.add("getAntdPaginationItem", getAntdPaginationItem);
Cypress.Commands.add("getTableRowExpandButton", getTableRowExpandButton);
Cypress.Commands.add(
"setAntdRangeDatePickerToToday",
setAntdRangeDatePickerToToday,
);
Cypress.Commands.add("fillChakraUIForm", fillChakraUIForm);
Cypress.Commands.add("getChakraUINotification", getChakraUINotification);
Cypress.Commands.add("getChakraUIToast", getChakraUIToast);
Cypress.Commands.add("getChakraUIFormItemError", getChakraUIFormItemError);
Cypress.Commands.add(
"getChakraUIPopoverDeleteButton",
getChakraUIPopoverDeleteButton,
);
Cypress.Commands.add("getChakraUILoadingOverlay", getChakraUILoadingOverlay);
Cypress.Commands.add("getMaterialUINotification", getMaterialUINotifications);
Cypress.Commands.add(
"getMaterialUIDeletePopoverButton",
getMaterialUIDeletePopoverButton,
);
Cypress.Commands.add("getMaterialUIFormItemError", getMaterialUIFormItemError);
Cypress.Commands.add(
"getMaterialUILoadingCircular",
getMaterialUILoadingCircular,
);
Cypress.Commands.add("getMaterialUIColumnHeader", getMaterialUIColumnHeader);
Cypress.Commands.add("fillMantineForm", fillMantineForm);
Cypress.Commands.add("getMantineNotification", getMantineNotification);
Cypress.Commands.add(
"getMantinePopoverDeleteButton",
getMantinePopoverDeleteButton,
);
Cypress.Commands.add("getMantineFormItemError", getMantineFormItemError);
Cypress.Commands.add("getMantineLoadingOverlay", getMantineLoadingOverlay);
Cypress.Commands.add("fillMaterialUIForm", fillMaterialUIForm);
/**
* Disable telemetry calls
*/
beforeEach(() => {
cy.intercept("https://telemetry.refine.dev/**", {
body: "Disabled telemetry to avoid unwanted entries in the database",
statusCode: 200,
}).as("telemetry");
});

View File

@@ -1,154 +0,0 @@
/// <reference types="cypress" />
type UITypes = "antd" | "material-ui" | "chakra-ui" | "mantine";
interface ISetAntdDropdownParams {
id: string;
selectIndex?: number;
}
interface ISetAntdSelectParams {
id: string;
value: string;
}
interface ISetAntdRangeDatePickerToTodayParams {
id: string;
}
interface IGetAntdFormItemErrorParams {
id: string;
}
interface IGetChakraUIFormItemErrorParams {
id: string;
type?: "text" | "select";
}
interface IGetMaterialUIFormItemErrorParams {
id: string;
}
interface IGetMantineFormItemErrorParams {
id: string;
}
interface IResourceCreateParams {
ui: UITypes;
}
interface IResourceEditParams {
ui: UITypes;
}
interface IResourceDeleteParams {
ui: UITypes;
}
type IAction = "list" | "edit" | "show" | "create" | "clone" | "default";
declare namespace Cypress {
interface Chainable {
resourceList(): Chainable<void>;
resourceCreate(
params: IResourceCreateParams,
): Chainable<JQuery<HTMLElement>>;
resourceEdit(
params: IResourceCreateParams,
): Chainable<JQuery<HTMLElement>>;
resourceShow(): Chainable<void>;
resourceDelete(params: IResourceCreateParams): Chainable<void>;
assertDocumentTitle(
resource: string,
action?: IAction,
): Chainable<void>;
getSaveButton(): Chainable<JQuery<HTMLElement>>;
getCreateButton(): Chainable<JQuery<HTMLElement>>;
getDeleteButton(): Chainable<JQuery<HTMLElement>>;
getEditButton(): Chainable<JQuery<HTMLElement>>;
getShowButton(): Chainable<JQuery<HTMLElement>>;
getPageHeaderTitle(): Chainable<JQuery<HTMLElement>>;
getAntdNotification(): Chainable<JQuery<HTMLElement>>;
getAntdLoadingOverlay(): Chainable<JQuery<HTMLElement>>;
getAntdPopoverDeleteButton(): Chainable<JQuery<HTMLElement>>;
getAntdColumnSorter(index: number): Chainable<JQuery<HTMLElement>>;
getAntdFilterTrigger(index: number): Chainable<JQuery<HTMLElement>>;
getAntdPaginationItem(index: number): Chainable<JQuery<HTMLElement>>;
getTableRowExpandButton(index: number): Chainable<JQuery<HTMLElement>>;
setAntdDropdown(
params: ISetAntdDropdownParams,
): Chainable<JQuery<HTMLElement>>;
setAntdSelect(
params: ISetAntdSelectParams,
): Chainable<JQuery<HTMLElement>>;
setAntdRangeDatePickerToToday(
params: ISetAntdRangeDatePickerToTodayParams,
): Chainable<JQuery<HTMLElement>>;
getAntdFormItemError(
params: IGetAntdFormItemErrorParams,
): Chainable<JQuery<HTMLElement>>;
fillAntdForm: () => void;
getChakraUINotification(): Chainable<JQuery<HTMLElement>>;
getChakraUIToast(): Chainable<JQuery<HTMLElement>>;
getChakraUIFormItemError(
params: IGetChakraUIFormItemErrorParams,
): Chainable<JQuery<HTMLElement>>;
getChakraUIDeletePopoverButton(): Chainable<JQuery<HTMLElement>>;
getChakraUILoadingOverlay(): Chainable<JQuery<HTMLElement>>;
getChakraUIPopoverDeleteButton(): Chainable<JQuery<HTMLElement>>;
fillChakraUIForm: () => void;
getMantineNotification(): Chainable<JQuery<HTMLElement>>;
getMantinePopoverDeleteButton(): Chainable<JQuery<HTMLElement>>;
getMantineFormItemError(
params: IGetMantineFormItemErrorParams,
): Chainable<JQuery<HTMLElement>>;
getMantineLoadingOverlay(): Chainable<JQuery<HTMLElement>>;
fillMantineForm: () => void;
getMaterialUINotification(): Chainable<JQuery<HTMLElement>>;
getMaterialUIDeletePopoverButton(): Chainable<JQuery<HTMLElement>>;
getMaterialUIFormItemError(
params: IGetChakraUIFormItemErrorParams,
): Chainable<JQuery<HTMLElement>>;
getMaterialUILoadingCircular(): Chainable<JQuery<HTMLElement>>;
getMaterialUIColumnHeader(
index: number,
): Chainable<JQuery<HTMLElement>>;
fillMaterialUIForm: () => void;
interceptGETBlogPost(): Chainable<null>;
interceptGETBlogPosts(): Chainable<null>;
interceptPOSTBlogPost(): Chainable<null>;
interceptPATCHBlogPost(): Chainable<null>;
interceptDELETEBlogPost(): Chainable<null>;
interceptGETPost(): Chainable<null>;
interceptGETPosts(): Chainable<null>;
interceptPOSTPost(): Chainable<null>;
interceptPATCHPost(): Chainable<null>;
interceptDELETEPost(): Chainable<null>;
interceptGETCategories(): Chainable<null>;
interceptGETCategory(): Chainable<null>;
interceptSupabaseGETPosts(): Chainable<null>;
interceptSupabasePOSTPost(): Chainable<null>;
interceptSupabasePATCHPost(): Chainable<null>;
interceptSupabaseDELETEPost(): Chainable<null>;
interceptSupabaseGETCategories(): Chainable<null>;
interceptStrapiV4GETPost(): Chainable<null>;
interceptStrapiV4GETPosts(): Chainable<null>;
interceptStrapiV4POSTPost(): Chainable<null>;
interceptStrapiV4PUTPost(): Chainable<null>;
interceptStrapiV4DELETEPost(): Chainable<null>;
interceptStrapiV4GETCategories(): Chainable<null>;
interceptStrapiV4GETCategory(): Chainable<null>;
interceptHasura(): Chainable<null>;
}
}

View File

@@ -1,5 +0,0 @@
import posts from "../../fixtures/posts.json";
import categories from "../../fixtures/categories.json";
export type IPost = (typeof posts)[number];
export type ICategory = (typeof categories)[number];

View File

@@ -1,4 +0,0 @@
export const getIdFromURL = (url: string) => {
const id = Number(url.split("/")?.pop()?.split("?")?.[0]);
return id;
};

View File

@@ -1 +0,0 @@
export * from "./getIdFromURL";

View File

@@ -1,11 +0,0 @@
node_modules
.DS_Store
test
jest.config.js
**/*.spec.ts
**/*.spec.tsx
**/*.test.ts
**/*.test.tsx
tsup.config.ts
tsconfig.test.json
tsconfig.declarations.json

View File

@@ -1,93 +0,0 @@
# @refinedev/ably
## 4.1.4
### Patch Changes
- [#5425](https://github.com/refinedev/refine/pull/5425) [`190af9fce2`](https://github.com/refinedev/refine/commit/190af9fce292bc46b169e3e121be6bf1c2a939a5) Thanks [@aliemir](https://github.com/aliemir)! - Updated `@refinedev/core` peer dependencies to latest (`^4.46.1`)
## 4.1.3
### Patch Changes
- [#5330](https://github.com/refinedev/refine/pull/5330) [`7c8827b43d`](https://github.com/refinedev/refine/commit/7c8827b43d9e378818be6ee23032925c97ce02d5) Thanks [@BatuhanW](https://github.com/BatuhanW)! - chore: upgrade nock library version to ^13.4.0
## 4.1.2
### Patch Changes
- [#5022](https://github.com/refinedev/refine/pull/5022) [`80513a4e42f`](https://github.com/refinedev/refine/commit/80513a4e42f8dda39e01157643594a9e4c32001b) Thanks [@BatuhanW](https://github.com/BatuhanW)! - chore: update README.md
- fix grammar errors.
- make all README.md files consistent.
- add code example code snippets.
## 4.1.1
### Patch Changes
- [#5022](https://github.com/refinedev/refine/pull/5022) [`80513a4e42f`](https://github.com/refinedev/refine/commit/80513a4e42f8dda39e01157643594a9e4c32001b) Thanks [@BatuhanW](https://github.com/BatuhanW)! - chore: update README.md
- fix grammar errors.
- make all README.md files consistent.
- add code example code snippets.
## 4.1.0
### Minor Changes
- Thanks [@aliemir](https://github.com/aliemir), [@alicanerdurmaz](https://github.com/alicanerdurmaz), [@batuhanW](https://github.com/batuhanW), [@salihozdemir](https://github.com/salihozdemir), [@yildirayunlu](https://github.com/yildirayunlu), [@recepkutuk](https://github.com/recepkutuk)!
**Moving to the `@refinedev` scope 🎉🎉**
Moved to the `@refinedev` scope and updated our packages to use the new scope. From now on, all packages will be published under the `@refinedev` scope with their new names.
Now, we're also removing the `refine` prefix from all packages. So, the `@pankod/refine-core` package is now `@refinedev/core`, `@pankod/refine-antd` is now `@refinedev/antd`, and so on.
### Patch Changes
## 3.31.0
### Minor Changes
- [#3822](https://github.com/refinedev/refine/pull/3822) [`0baa99ba787`](https://github.com/refinedev/refine/commit/0baa99ba7874394d9d28d0a7b29c082c604258fb) Thanks [@BatuhanW](https://github.com/BatuhanW)! - - refine v4 release announcement added to "postinstall". - refine v4 is released 🎉 The new version is 100% backward compatible. You can upgrade to v4 with a single command! See the migration guide here: https://refine.dev/docs/migration-guide/3x-to-4x
## 3.30.0
### Minor Changes
- [#3822](https://github.com/refinedev/refine/pull/3822) [`0baa99ba787`](https://github.com/refinedev/refine/commit/0baa99ba7874394d9d28d0a7b29c082c604258fb) Thanks [@BatuhanW](https://github.com/BatuhanW)! - - refine v4 release announcement added to "postinstall". - refine v4 is released 🎉 The new version is 100% backward compatible. You can upgrade to v4 with a single command! See the migration guide here: https://refine.dev/docs/migration-guide/3x-to-4x
## 3.29.0
### Minor Changes
- Update type declaration generation with `tsc` instead of `tsup` for better navigation throughout projects source code.
## 3.28.0
### Minor Changes
- [#2440](https://github.com/refinedev/refine/pull/2440) [`0150dcd070`](https://github.com/refinedev/refine/commit/0150dcd0700253f1c4908e7e5f2e178bb122e9af) Thanks [@aliemir](https://github.com/aliemir)! - Update type declaration generation with `tsc` instead of `tsup` for better navigation throughout projects source code.
## 3.27.0
### Minor Changes
- All of the refine packages have dependencies on the `@pankod/refine-core` package. So far we have managed these dependencies with `peerDependencies` + `dependencies` but this causes issues like #2183. (having more than one @pankod/refine-core version in node_modules and creating different instances)
Managing as `peerDependencies` + `devDependencies` seems like the best way for now to avoid such issues.
## 3.26.0
### Minor Changes
- [#2217](https://github.com/refinedev/refine/pull/2217) [`b4aae00f77`](https://github.com/refinedev/refine/commit/b4aae00f77a2476d847994db21298ae25e4cf6e5) Thanks [@omeraplak](https://github.com/omeraplak)! - All of the refine packages have dependencies on the `@pankod/refine-core` package. So far we have managed these dependencies with `peerDependencies` + `dependencies` but this causes issues like #2183. (having more than one @pankod/refine-core version in node_modules and creating different instances)
Managing as `peerDependencies` + `devDependencies` seems like the best way for now to avoid such issues.
## 3.22.2
### Patch Changes
- Updated dependencies [[`2deb19babf`](https://github.com/refinedev/refine/commit/2deb19babfc6db5b00b111ec29aa5ece4c371bbc)]:
- @pankod/refine-core@3.23.2

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2022 Refine Development Inc.
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.

View File

@@ -1,74 +0,0 @@
<div align="center" style="margin: 30px;">
<a href="https://refine.dev">
<img alt="refine logo" src="https://refine.ams3.cdn.digitaloceanspaces.com/readme/refine-readme-banner.png">
</a>
</div>
<br/>
<div align="center">
<a href="https://refine.dev">Home Page</a> |
<a href="https://discord.gg/refine">Discord</a> |
<a href="https://refine.dev/examples/">Examples</a> |
<a href="https://refine.dev/blog/">Blog</a> |
<a href="https://refine.dev/docs/">Documentation</a>
<br/>
<br/>
[![Discord](https://img.shields.io/discord/837692625737613362.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/refine)
[![Twitter Follow](https://img.shields.io/twitter/follow/refine_dev?style=social)](https://twitter.com/refine_dev)
<a href="https://www.producthunt.com/posts/refine-3?utm_source=badge-top-post-badge&utm_medium=badge&utm_souce=badge-refine&#0045;3" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/top-post-badge.svg?post_id=362220&theme=light&period=daily" alt="refine - 100&#0037;&#0032;open&#0032;source&#0032;React&#0032;framework&#0032;to&#0032;build&#0032;web&#0032;apps&#0032;3x&#0032;faster | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
</div>
<br/>
<div align="center">refine is an open-source, headless React framework for developers building enterprise internal tools, admin panels, dashboards, B2B applications.
<br/>
It eliminates repetitive tasks in CRUD operations and provides industry-standard solutions for critical project components like **authentication**, **access control**, **routing**, **networking**, **state management**, and **i18n**.
</div>
<br/>
# Ably integration for refine
[Ably](https://ably.com/) reliably distributes realtime data to your users using the publish/subscribe messaging pattern over WebSocket connections.
[refine](https://refine.dev/) is **headless by design**, offering unlimited styling and customization options. Moreover, refine ships with ready-made integrations for [Ant Design](https://ant.design/), [Material UI](https://mui.com/material-ui/getting-started/overview/), [Mantine](https://mantine.dev/), and [Chakra UI](https://chakra-ui.com/) for convenience.
refine has connectors for 15+ backend services, including REST API, [GraphQL](https://graphql.org/), and popular services like [Airtable](https://www.airtable.com/), [Strapi](https://strapi.io/), [Supabase](https://supabase.com/), [Firebase](https://firebase.google.com/), and [NestJS](https://nestjs.com/).
## Installation & Usage
```
npm install @refinedev/ably
```
```tsx
import { liveProvider, Ably } from "@refinedev/ably";
export const ablyClient = new Ably.Realtime("YOUR_API_TOKEN");
const App = () => {
return (
<Refine
liveProvider={liveProvider(ablyClient)}
/* ... */
>
{/* ... */}
</Refine>
);
};
```
## Documentation
- For more detailed information and usage, refer to the [refine live provider documentation](https://refine.dev/docs/api-references/providers/live-provider/).
- Refer to refine & Ably tutorial on [official Ably docs](https://ably.com/tutorials/react-admin-panel-with-ably-and-refine).
- [Refer to documentation for more info about refine](https://refine.dev/docs/).
- [Step up to refine tutorials](https://refine.dev/docs/tutorial/introduction/index/).

View File

@@ -1,6 +0,0 @@
module.exports = {
preset: "ts-jest",
rootDir: "./",
displayName: "ably",
testEnvironment: "jsdom",
};

View File

@@ -1,50 +0,0 @@
{
"name": "@refinedev/ably",
"description": "refine ably live provider. refine is a React-based framework for building internal tools, rapidly. It ships with Ant Design System, an enterprise-level UI toolkit.",
"version": "4.1.4",
"license": "MIT",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"private": false,
"files": [
"dist",
"src"
],
"engines": {
"node": ">=10"
},
"scripts": {
"start": "tsup --watch --format esm,cjs,iife --legacy-output",
"build": "tsup --format esm,cjs,iife --minify --legacy-output",
"test": "jest --passWithNoTests --runInBand",
"prepare": "npm run build"
},
"author": "refine",
"module": "dist/esm/index.js",
"devDependencies": {
"@refinedev/core": "^4.46.1",
"@esbuild-plugins/node-resolve": "^0.1.4",
"@types/jest": "^29.2.4",
"jest": "^29.3.1",
"jest-environment-jsdom": "^29.3.1",
"nock": "^13.4.0",
"ts-jest": "^29.0.3",
"tslib": "^2.3.1",
"tsup": "^6.7.0"
},
"dependencies": {
"ably": "^1.2.15"
},
"peerDependencies": {
"@refinedev/core": "^4.46.1"
},
"repository": {
"type": "git",
"url": "https://github.com/refinedev/refine.git",
"directory": "packages/ably"
},
"gitHead": "829f5a516f98c06f666d6be3e6e6099c75c07719",
"publishConfig": {
"access": "public"
}
}

View File

@@ -1,57 +0,0 @@
import { LiveProvider, LiveEvent } from "@refinedev/core";
import Ably from "ably/promises";
import { Types } from "ably";
interface MessageType extends Types.Message {
data: LiveEvent;
}
const liveProvider = (client: Ably.Realtime): LiveProvider => {
return {
subscribe: ({ channel, types, params, callback }) => {
const channelInstance = client.channels.get(channel);
const listener = function (message: MessageType) {
if (types.includes("*") || types.includes(message.data.type)) {
if (
message.data.type !== "created" &&
params?.ids !== undefined &&
message.data?.payload?.ids !== undefined
) {
if (
params.ids
.map(String)
.filter((value) =>
message.data.payload.ids
?.map(String)
.includes(value),
).length > 0
) {
callback(message.data as LiveEvent);
}
} else {
callback(message.data);
}
}
};
channelInstance.subscribe(listener);
return { channelInstance, listener };
},
unsubscribe: (payload: {
channelInstance: Types.RealtimeChannelPromise;
listener: () => void;
}) => {
const { channelInstance, listener } = payload;
channelInstance.unsubscribe(listener);
},
publish: (event: LiveEvent) => {
const channelInstance = client.channels.get(event.channel);
channelInstance.publish(event.type, event);
},
};
};
export { liveProvider, Ably };

View File

@@ -1,21 +0,0 @@
{
"extends": "./tsconfig.json",
"exclude": [
"node_modules",
"dist",
"test",
"../test/**/*",
"**/*.spec.ts",
"**/*.test.ts",
"**/*.spec.tsx",
"**/*.test.tsx"
],
"compilerOptions": {
"outDir": "dist",
"declarationDir": "dist",
"declaration": true,
"emitDeclarationOnly": true,
"noEmit": false,
"declarationMap": true
}
}

View File

@@ -1,11 +0,0 @@
{
"include": [
"src",
"types"
],
"extends": "../../tsconfig.build.json",
"compilerOptions": {
"rootDir": "./src",
"baseUrl": ".",
}
}

View File

@@ -1,24 +0,0 @@
import { defineConfig } from "tsup";
import { NodeResolvePlugin } from "@esbuild-plugins/node-resolve";
export default defineConfig({
entry: ["src/index.ts"],
splitting: false,
sourcemap: true,
clean: false,
platform: "browser",
esbuildPlugins: [
NodeResolvePlugin({
extensions: [".js", "ts", "tsx", "jsx"],
onResolved: (resolved) => {
if (resolved.includes("node_modules")) {
return {
external: true,
};
}
return resolved;
},
}),
],
onSuccess: "tsc --project tsconfig.declarations.json",
});

View File

@@ -1,11 +0,0 @@
node_modules
.DS_Store
test
jest.config.js
**/*.spec.ts
**/*.spec.tsx
**/*.test.ts
**/*.test.tsx
tsup.config.ts
tsconfig.test.json
tsconfig.declarations.json

View File

@@ -1,357 +0,0 @@
# @refinedev/airtable
## 4.4.6
### Patch Changes
- [#5425](https://github.com/refinedev/refine/pull/5425) [`190af9fce2`](https://github.com/refinedev/refine/commit/190af9fce292bc46b169e3e121be6bf1c2a939a5) Thanks [@aliemir](https://github.com/aliemir)! - Updated `@refinedev/core` peer dependencies to latest (`^4.46.1`)
## 4.4.5
### Patch Changes
- [#5330](https://github.com/refinedev/refine/pull/5330) [`7c8827b43d`](https://github.com/refinedev/refine/commit/7c8827b43d9e378818be6ee23032925c97ce02d5) Thanks [@BatuhanW](https://github.com/BatuhanW)! - chore: upgrade nock library version to ^13.4.0
## 4.4.4
### Patch Changes
- [#5022](https://github.com/refinedev/refine/pull/5022) [`80513a4e42f`](https://github.com/refinedev/refine/commit/80513a4e42f8dda39e01157643594a9e4c32001b) Thanks [@BatuhanW](https://github.com/BatuhanW)! - chore: update README.md
- fix grammar errors.
- make all README.md files consistent.
- add code example code snippets.
## 4.4.3
### Patch Changes
- [#5022](https://github.com/refinedev/refine/pull/5022) [`80513a4e42f`](https://github.com/refinedev/refine/commit/80513a4e42f8dda39e01157643594a9e4c32001b) Thanks [@BatuhanW](https://github.com/BatuhanW)! - chore: update README.md
- fix grammar errors.
- make all README.md files consistent.
- add code example code snippets.
## 4.4.2
### Patch Changes
- [#4285](https://github.com/refinedev/refine/pull/4285) [`b5cd3328504`](https://github.com/refinedev/refine/commit/b5cd332850428383e8b43f997cbb0340ac7f0dc6) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - fixed: A bug that prevented data providers from being swizzled.
## 4.4.1
### Patch Changes
- [#4285](https://github.com/refinedev/refine/pull/4285) [`b5cd3328504`](https://github.com/refinedev/refine/commit/b5cd332850428383e8b43f997cbb0340ac7f0dc6) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - fixed: A bug that prevented data providers from being swizzled.
## 4.4.0
### Minor Changes
- [#4276](https://github.com/refinedev/refine/pull/4276) [`740cef82e9e`](https://github.com/refinedev/refine/commit/740cef82e9e71274edb4be1d6936a2b74b73b4ec) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - feat: added swizzle to airtable
## 4.3.0
### Minor Changes
- [#4276](https://github.com/refinedev/refine/pull/4276) [`740cef82e9e`](https://github.com/refinedev/refine/commit/740cef82e9e71274edb4be1d6936a2b74b73b4ec) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - feat: added swizzle to airtable
## 4.2.0
### Minor Changes
- [#4276](https://github.com/refinedev/refine/pull/4276) [`740cef82e9e`](https://github.com/refinedev/refine/commit/740cef82e9e71274edb4be1d6936a2b74b73b4ec) Thanks [@alicanerdurmaz](https://github.com/alicanerdurmaz)! - feat: added swizzle to airtable
## 4.1.0
### Minor Changes
- Thanks [@aliemir](https://github.com/aliemir), [@alicanerdurmaz](https://github.com/alicanerdurmaz), [@batuhanW](https://github.com/batuhanW), [@salihozdemir](https://github.com/salihozdemir), [@yildirayunlu](https://github.com/yildirayunlu), [@recepkutuk](https://github.com/recepkutuk)!
- `metaData` prop is now deprecated for all data provider methods. Use `meta` prop instead.
> For backward compatibility, we still support `metaData` prop with refine v4.
```diff
create: async ({
- metaData
+ meta
}) => {
...
},
```
- `sort`, `hasPagination`, and `metaData` parameters of `getList` method are now deprecated. Use `sorters`, `pagination`, and `meta` parameters instead.
> For backward compatibility, we still support `sort`, `hasPagination` and `metaData` props with refine v4.
```diff
getList: async ({
- sort
+ sorters
- hasPagination
+ pagination: { mode: "off" | "server | "client" }
- metaData
+ meta
}) => {
...
},
```
- Thanks [@aliemir](https://github.com/aliemir), [@alicanerdurmaz](https://github.com/alicanerdurmaz), [@batuhanW](https://github.com/batuhanW), [@salihozdemir](https://github.com/salihozdemir), [@yildirayunlu](https://github.com/yildirayunlu), [@recepkutuk](https://github.com/recepkutuk)!
**Moving to the `@refinedev` scope 🎉🎉**
Moved to the `@refinedev` scope and updated our packages to use the new scope. From now on, all packages will be published under the `@refinedev` scope with their new names.
Now, we're also removing the `refine` prefix from all packages. So, the `@pankod/refine-core` package is now `@refinedev/core`, `@pankod/refine-antd` is now `@refinedev/antd`, and so on.
### Patch Changes
## 3.35.0
### Minor Changes
- [#3822](https://github.com/refinedev/refine/pull/3822) [`0baa99ba787`](https://github.com/refinedev/refine/commit/0baa99ba7874394d9d28d0a7b29c082c604258fb) Thanks [@BatuhanW](https://github.com/BatuhanW)! - - refine v4 release announcement added to "postinstall". - refine v4 is released 🎉 The new version is 100% backward compatible. You can upgrade to v4 with a single command! See the migration guide here: https://refine.dev/docs/migration-guide/3x-to-4x
## 3.34.0
### Minor Changes
- [#3822](https://github.com/refinedev/refine/pull/3822) [`0baa99ba787`](https://github.com/refinedev/refine/commit/0baa99ba7874394d9d28d0a7b29c082c604258fb) Thanks [@BatuhanW](https://github.com/BatuhanW)! - - refine v4 release announcement added to "postinstall". - refine v4 is released 🎉 The new version is 100% backward compatible. You can upgrade to v4 with a single command! See the migration guide here: https://refine.dev/docs/migration-guide/3x-to-4x
## 3.33.0
### Minor Changes
- Only `or` was supported as a conditional filter. Now `and` and `or` can be used together and nested. 🚀
```
{
operator: "or",
value: [
{
operator: "and",
value: [
{
field: "name",
operator: "eq",
value: "John Doe",
},
{
field: "age",
operator: "eq",
value: 30,
},
],
},
{
operator: "and",
value: [
{
field: "name",
operator: "eq",
value: "JR Doe",
},
{
field: "age",
operator: "eq",
value: 1,
},
],
},
],
}
```
## 3.32.0
### Minor Changes
- [#2751](https://github.com/refinedev/refine/pull/2751) [`addff64c77`](https://github.com/refinedev/refine/commit/addff64c777e4c9f044a1a109cb05453e6e9f762) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - Only `or` was supported as a conditional filter. Now `and` and `or` can be used together and nested. 🚀
```
{
operator: "or",
value: [
{
operator: "and",
value: [
{
field: "name",
operator: "eq",
value: "John Doe",
},
{
field: "age",
operator: "eq",
value: 30,
},
],
},
{
operator: "and",
value: [
{
field: "name",
operator: "eq",
value: "JR Doe",
},
{
field: "age",
operator: "eq",
value: 1,
},
],
},
],
}
```
## 3.31.0
### Minor Changes
- Updated `dataProvider` types with `Required` utility to mark `getMany`, `createMany`, `updateMany` and `deleteMany` as implemented.
## 3.30.0
### Minor Changes
- [#2688](https://github.com/refinedev/refine/pull/2688) [`508045ac30`](https://github.com/refinedev/refine/commit/508045ac30cd3948f68497e13fdf04f7c72ce387) Thanks [@aliemir](https://github.com/aliemir)! - Updated `dataProvider` types with `Required` utility to mark `getMany`, `createMany`, `updateMany` and `deleteMany` as implemented.
## 3.29.0
### Minor Changes
- Update type declaration generation with `tsc` instead of `tsup` for better navigation throughout projects source code.
## 3.28.0
### Minor Changes
- [#2440](https://github.com/refinedev/refine/pull/2440) [`0150dcd070`](https://github.com/refinedev/refine/commit/0150dcd0700253f1c4908e7e5f2e178bb122e9af) Thanks [@aliemir](https://github.com/aliemir)! - Update type declaration generation with `tsc` instead of `tsup` for better navigation throughout projects source code.
## 3.27.0
### Minor Changes
- All of the refine packages have dependencies on the `@pankod/refine-core` package. So far we have managed these dependencies with `peerDependencies` + `dependencies` but this causes issues like #2183. (having more than one @pankod/refine-core version in node_modules and creating different instances)
Managing as `peerDependencies` + `devDependencies` seems like the best way for now to avoid such issues.
## 3.26.0
### Minor Changes
- [#2217](https://github.com/refinedev/refine/pull/2217) [`b4aae00f77`](https://github.com/refinedev/refine/commit/b4aae00f77a2476d847994db21298ae25e4cf6e5) Thanks [@omeraplak](https://github.com/omeraplak)! - All of the refine packages have dependencies on the `@pankod/refine-core` package. So far we have managed these dependencies with `peerDependencies` + `dependencies` but this causes issues like #2183. (having more than one @pankod/refine-core version in node_modules and creating different instances)
Managing as `peerDependencies` + `devDependencies` seems like the best way for now to avoid such issues.
## 3.25.6
### Patch Changes
- Updated pagination parameters default values and added `hasPagination` property to `getList` method of the data providers.
**Implementation**
Updated the `getList` method accordingly to the changes in the `useTable` and `useList` of `@pankod/refine-core`. `hasPagination` is used to disable pagination (defaults to `true`)
**Use Cases**
For some resources, there might be no support for pagination or users might want to see all of the data without any pagination, prior to these changes this was not supported in **refine** data providers.
- Updated dependencies []:
- @pankod/refine-core@3.36.0
## 3.25.5
### Patch Changes
- [#2050](https://github.com/refinedev/refine/pull/2050) [`635cfe9fdb`](https://github.com/refinedev/refine/commit/635cfe9fdbfe5940b950ae99c1f0b686c78bb8e5) Thanks [@ozkalai](https://github.com/ozkalai)! - Updated pagination parameters default values and added `hasPagination` property to `getList` method of the data providers.
**Implementation**
Updated the `getList` method accordingly to the changes in the `useTable` and `useList` of `@pankod/refine-core`. `hasPagination` is used to disable pagination (defaults to `true`)
**Use Cases**
For some resources, there might be no support for pagination or users might want to see all of the data without any pagination, prior to these changes this was not supported in **refine** data providers.
- Updated dependencies [[`ecde34a9b3`](https://github.com/refinedev/refine/commit/ecde34a9b38ef5667fa863f9ebb9dcb1cfff1651), [`635cfe9fdb`](https://github.com/refinedev/refine/commit/635cfe9fdbfe5940b950ae99c1f0b686c78bb8e5)]:
- @pankod/refine-core@3.35.0
## 3.25.4
### Patch Changes
- Updated axios version (0.21.4 to 0.26.1). In this version, the way of sending headers has changed as follows.
```
// old v0.21.4
axiosInstance.defaults.headers = { Authorization: `Bearer ${data.jwt}` };
// new v0.26.1
axiosInstance.defaults.headers.common["Authorization"] = `Bearer ${data.jwt}`;
```
- Updated dependencies []:
- @pankod/refine-core@3.29.0
## 3.25.3
### Patch Changes
- Updated axios version (0.21.4 to 0.26.1). In this version, the way of sending headers has changed as follows.
```
// old v0.21.4
axiosInstance.defaults.headers = { Authorization: `Bearer ${data.jwt}` };
// new v0.26.1
axiosInstance.defaults.headers.common["Authorization"] = `Bearer ${data.jwt}`;
```
- Updated dependencies []:
- @pankod/refine-core@3.28.0
## 3.25.2
### Patch Changes
- Updated axios version (0.21.4 to 0.26.1). In this version, the way of sending headers has changed as follows.
```
// old v0.21.4
axiosInstance.defaults.headers = { Authorization: `Bearer ${data.jwt}` };
// new v0.26.1
axiosInstance.defaults.headers.common["Authorization"] = `Bearer ${data.jwt}`;
```
- Updated dependencies []:
- @pankod/refine-core@3.27.0
## 3.25.1
### Patch Changes
- [#1899](https://github.com/refinedev/refine/pull/1899) [`fbfea418a0`](https://github.com/refinedev/refine/commit/fbfea418a024a527a2b432c634f46a96d4f70d88) Thanks [@yildirayunlu](https://github.com/yildirayunlu)! - Updated axios version (0.21.4 to 0.26.1). In this version, the way of sending headers has changed as follows.
```
// old v0.21.4
axiosInstance.defaults.headers = { Authorization: `Bearer ${data.jwt}` };
// new v0.26.1
axiosInstance.defaults.headers.common["Authorization"] = `Bearer ${data.jwt}`;
```
- Updated dependencies [[`2ba2a96fd2`](https://github.com/refinedev/refine/commit/2ba2a96fd24aa733c355ac9ef4c99b7d48115746)]:
- @pankod/refine-core@3.26.0
## 3.22.2
### Patch Changes
- Updated dependencies [[`2deb19babf`](https://github.com/refinedev/refine/commit/2deb19babfc6db5b00b111ec29aa5ece4c371bbc)]:
- @pankod/refine-core@3.23.2

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2022 Refine Development Inc.
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.

View File

@@ -1,70 +0,0 @@
<div align="center" style="margin: 30px;">
<a href="https://refine.dev">
<img alt="refine logo" src="https://refine.ams3.cdn.digitaloceanspaces.com/readme/refine-readme-banner.png">
</a>
</div>
<br/>
<div align="center">
<a href="https://refine.dev">Home Page</a> |
<a href="https://discord.gg/refine">Discord</a> |
<a href="https://refine.dev/examples/">Examples</a> |
<a href="https://refine.dev/blog/">Blog</a> |
<a href="https://refine.dev/docs/">Documentation</a>
<br/>
<br/>
[![Discord](https://img.shields.io/discord/837692625737613362.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/refine)
[![Twitter Follow](https://img.shields.io/twitter/follow/refine_dev?style=social)](https://twitter.com/refine_dev)
<a href="https://www.producthunt.com/posts/refine-3?utm_source=badge-top-post-badge&utm_medium=badge&utm_souce=badge-refine&#0045;3" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/top-post-badge.svg?post_id=362220&theme=light&period=daily" alt="refine - 100&#0037;&#0032;open&#0032;source&#0032;React&#0032;framework&#0032;to&#0032;build&#0032;web&#0032;apps&#0032;3x&#0032;faster | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
</div>
<br/>
<div align="center">refine is an open-source, headless React framework for developers building enterprise internal tools, admin panels, dashboards, B2B applications.
<br/>
It eliminates repetitive tasks in CRUD operations and provides industry-standard solutions for critical project components like **authentication**, **access control**, **routing**, **networking**, **state management**, and **i18n**.
</div>
# Airtable integration for refine
[Airtable](https://www.airtable.com/) is a cloud-based platform for creating and sharing relational databases.
[refine](https://refine.dev/) is **headless by design**, offering unlimited styling and customization options. Moreover, refine ships with ready-made integrations for [Ant Design](https://ant.design/), [Material UI](https://mui.com/material-ui/getting-started/overview/), [Mantine](https://mantine.dev/), and [Chakra UI](https://chakra-ui.com/) for convenience.
refine has connectors for 15+ backend services, including REST API, [GraphQL](https://graphql.org/), and popular services like [Airtable](https://www.airtable.com/), [Strapi](https://strapi.io/), [Supabase](https://supabase.com/), [Firebase](https://firebase.google.com/), and [NestJS](https://nestjs.com/).
## Installation & Usage
```
npm install @refinedev/airtable
```
```tsx
import dataProvider from "@refinedev/airtable";
const App = () => {
return (
<Refine
dataProvider={dataProvider("API_KEY", "BASE_ID")}
/* ... */
>
{/* ... */}
</Refine>
);
};
```
## Documentation
- For more detailed information and usage, refer to the [refine data provider documentation](https://refine.dev/docs/core/providers/data-provider).
- [Refer to refine Airtable example](https://refine.dev/docs/examples/data-provider/airtable/).
- [Refer to documentation for more info about refine](https://refine.dev/docs/).
- [Step up to refine tutorials](https://refine.dev/docs/tutorial/introduction/index/).

View File

@@ -1,7 +0,0 @@
module.exports = {
preset: "ts-jest",
rootDir: "./",
displayName: "airtable",
setupFilesAfterEnv: ["<rootDir>/test/jest.setup.js"],
testEnvironment: "jsdom",
};

View File

@@ -1,54 +0,0 @@
{
"name": "@refinedev/airtable",
"description": "refine Airtable data provider. refine is a React-based framework for building internal tools, rapidly. It ships with Ant Design System, an enterprise-level UI toolkit.",
"version": "4.4.6",
"license": "MIT",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"private": false,
"files": [
"dist",
"src",
"./refine.config.js"
],
"engines": {
"node": ">=10"
},
"scripts": {
"start": "tsup --watch --format esm,cjs,iife --legacy-output",
"build": "tsup --format esm,cjs,iife --minify --legacy-output",
"test": "jest --passWithNoTests --runInBand",
"prepare": "npm run build"
},
"author": "refine",
"module": "dist/esm/index.js",
"devDependencies": {
"@refinedev/core": "4.46.2",
"@esbuild-plugins/node-resolve": "^0.1.4",
"@types/jest": "^29.2.4",
"jest": "^29.3.1",
"jest-environment-jsdom": "^29.3.1",
"nock": "^13.4.0",
"ts-jest": "^29.0.3",
"tslib": "^2.3.1",
"tsup": "^6.7.0"
},
"dependencies": {
"@qualifyze/airtable-formulator": "^1.0.1",
"airtable": "^0.11.1",
"asyncairtable": "^2.1.0",
"query-string": "^7.1.1"
},
"peerDependencies": {
"@refinedev/core": "^4.46.1"
},
"repository": {
"type": "git",
"url": "https://github.com/refinedev/refine.git",
"directory": "packages/airtable"
},
"gitHead": "829f5a516f98c06f666d6be3e6e6099c75c07719",
"publishConfig": {
"access": "public"
}
}

View File

@@ -1,80 +0,0 @@
/** @type {import('@refinedev/cli').RefineConfig} */
module.exports = {
group: "Data Provider",
swizzle: {
items: [
{
label: "Data Provider",
requiredPackages: [
"@qualifyze/airtable-formulator@1.0.1",
"airtable@0.11.1",
"asyncairtable@2.1.0",
"query-string@7.1.1",
],
files: [
{
src: "./src/index.ts",
dest: "./providers/airtable/index.ts",
},
{
src: "./src/dataProvider.ts",
dest: "./providers/airtable/dataProvider.ts",
},
{
src: "./src/utils/index.ts",
dest: "./providers/airtable/utils/index.ts",
},
{
src: "./src/utils/generateFilter.ts",
dest: "./providers/airtable/utils/generateFilter.ts",
},
{
src: "./src/utils/generateFilterFormula.ts",
dest: "./providers/airtable/utils/generateFilterFormula.ts",
},
{
src: "./src/utils/generateLogicalFilterFormula.ts",
dest: "./providers/airtable/utils/generateLogicalFilterFormula.ts",
},
{
src: "./src/utils/generateLogicalFilterFormula.ts",
dest: "./providers/airtable/utils/generateLogicalFilterFormula.ts",
},
{
src: "./src/utils/generateSort.ts",
dest: "./providers/airtable/utils/generateSort.ts",
},
{
src: "./src/utils/isContainsOperator.ts",
dest: "./providers/airtable/utils/isContainsOperator.ts",
},
{
src: "./src/utils/isSimpleOperator.ts",
dest: "./providers/airtable/utils/isSimpleOperator.ts",
},
],
message: `
**\`Usage\`**
\`\`\`
// title: App.tsx
import { dataProvider } from "./providers/airtable";
const API_TOKEN = "dummy-api-token";
const BASE_ID = "dummy-base-id";
const App = () => {
return (
<Refine
dataProvider={dataProvider(API_TOKEN, BASE_ID)}
/* ... */
/>
);
}
\`\`\`
`,
},
],
},
};

View File

@@ -1,161 +0,0 @@
import { DataProvider } from "@refinedev/core";
import Airtable from "airtable";
import { AirtableBase } from "airtable/lib/airtable_base";
import { generateSort, generateFilter } from "./utils";
export const dataProvider = (
apiKey: string,
baseId: string,
airtableClient?: AirtableBase,
): Required<DataProvider> => {
const base =
airtableClient || new Airtable({ apiKey: apiKey }).base(baseId);
return {
getList: async ({ resource, pagination, sorters, filters }) => {
const {
current = 1,
pageSize = 10,
mode = "server",
} = pagination ?? {};
const generatedSort = generateSort(sorters) || [];
const queryFilters = generateFilter(filters);
const { all } = base(resource).select({
pageSize: 100,
sort: generatedSort,
...(queryFilters ? { filterByFormula: queryFilters } : {}),
});
const data = await all();
const isServerPaginationEnabled = mode === "server";
return {
data: data
.slice(
isServerPaginationEnabled
? (current - 1) * pageSize
: undefined,
isServerPaginationEnabled
? current * pageSize
: undefined,
)
.map((p) => ({
id: p.id,
...p.fields,
})) as any,
total: data.length,
};
},
getMany: async ({ resource, ids }) => {
const { all } = base(resource).select({
pageSize: 100,
});
const data = await all();
return {
data: data
.filter((p) => ids.includes(p.id))
.map((p) => ({
id: p.id,
...p.fields,
})) as any,
};
},
create: async ({ resource, variables }) => {
const { id, fields } = await base(resource).create(variables);
return {
data: {
id: id,
...fields,
} as any,
};
},
createMany: async ({ resource, variables }) => {
const data = await base(resource).create(variables);
return {
data: data.map((p) => ({
id: p.id,
...p.fields,
})) as any,
};
},
update: async ({ resource, id, variables }) => {
const { fields } = await base(resource).update(
id.toString(),
variables,
);
return {
data: {
id,
...fields,
} as any,
};
},
updateMany: async ({ resource, ids, variables }) => {
const requestParams = ids.map((id) => ({
id: id.toString(),
fields: { ...variables },
}));
const data = await base(resource).update(requestParams);
return {
data: data.map((p) => ({
id: p.id,
...p.fields,
})) as any,
};
},
getOne: async ({ resource, id }) => {
const { fields } = await base(resource).find(id.toString());
return {
data: {
id,
...fields,
} as any,
};
},
deleteOne: async ({ resource, id }) => {
const { fields } = await base(resource).destroy(id.toString());
return {
data: {
id,
...fields,
} as any,
};
},
deleteMany: async ({ resource, ids }) => {
const data = await base(resource).destroy(ids.map(String));
return {
data: data.map((p) => ({
id: p.id,
...p.fields,
})) as any,
};
},
getApiUrl: () => {
throw Error("Not implemented on refine-airtable data provider.");
},
custom: async () => {
throw Error("Not implemented on refine-airtable data provider.");
},
};
};

View File

@@ -1,5 +0,0 @@
import { dataProvider } from "./dataProvider";
export * from "./utils";
export * from "./dataProvider";
export default dataProvider;

View File

@@ -1,12 +0,0 @@
import { CrudFilters } from "@refinedev/core";
import { compile } from "@qualifyze/airtable-formulator";
import { generateFilterFormula } from "./generateFilterFormula";
export const generateFilter = (filters?: CrudFilters): string | undefined => {
if (filters) {
// Top-level array has an implicit AND as per CRUDFilter design - https://refine.dev/docs/guides-and-concepts/data-provider/handling-filters/#logicalfilters
return compile(["AND", ...generateFilterFormula(filters)]);
}
return undefined;
};

View File

@@ -1,17 +0,0 @@
import { CrudFilters, LogicalFilter } from "@refinedev/core";
import { Formula } from "@qualifyze/airtable-formulator";
import { generateLogicalFilterFormula } from "./generateLogicalFilterFormula";
export const generateFilterFormula = (filters: CrudFilters): Formula[] => {
const compound = filters.map((filter): Formula => {
const { operator, value } = filter;
if (operator === "or") {
return ["OR", ...generateFilterFormula(value)];
}
return generateLogicalFilterFormula(filter as LogicalFilter);
});
return compound;
};

View File

@@ -1,50 +0,0 @@
import { LogicalFilter } from "@refinedev/core";
import { isContainsOperator, isContainssOperator } from "./isContainsOperator";
import { isSimpleOperator, simpleOperatorMapping } from "./isSimpleOperator";
import { Formula } from "@qualifyze/airtable-formulator";
export const generateLogicalFilterFormula = (
filter: LogicalFilter,
): Formula => {
const { field, operator, value } = filter;
if (isSimpleOperator(operator)) {
return [simpleOperatorMapping[operator], { field }, value];
}
if (isContainssOperator(operator)) {
const mappedOperator = {
containss: "!=",
ncontainss: "=",
} as const;
return [mappedOperator[operator], ["FIND", value, { field }], 0];
}
if (isContainsOperator(operator)) {
const mappedOperator = {
contains: "!=",
ncontains: "=",
} as const;
const find = [
"FIND",
["LOWER", value],
["LOWER", { field }],
] as Formula;
return [mappedOperator[operator], find, 0];
}
if (operator === "null") {
return ["=", { field }, ["BLANK"]];
}
if (operator === "nnull") {
return ["!=", { field }, ["BLANK"]];
}
throw Error(
`Operator ${operator} is not supported for the Airtable data provider`,
);
};

View File

@@ -1,8 +0,0 @@
import { CrudSorting } from "@refinedev/core";
export const generateSort = (sorters?: CrudSorting) => {
return sorters?.map((item) => ({
field: item.field,
direction: item.order,
}));
};

View File

@@ -1,6 +0,0 @@
export * from "./isSimpleOperator";
export * from "./isContainsOperator";
export * from "./generateLogicalFilterFormula";
export * from "./generateFilterFormula";
export * from "./generateFilter";
export * from "./generateSort";

View File

@@ -1,9 +0,0 @@
export const isContainssOperator = (
operator: any,
): operator is "containss" | "ncontainss" =>
["containss", "ncontainss"].includes(operator);
export const isContainsOperator = (
operator: any,
): operator is "contains" | "ncontains" =>
["contains", "ncontains"].includes(operator);

View File

@@ -1,14 +0,0 @@
export type SimpleOperators = "eq" | "ne" | "lt" | "lte" | "gt" | "gte";
import { OperatorSymbol } from "@qualifyze/airtable-formulator";
export const simpleOperatorMapping: Record<SimpleOperators, OperatorSymbol> = {
eq: "=",
ne: "!=",
lt: "<",
lte: "<=",
gt: ">",
gte: ">=",
} as const;
export const isSimpleOperator = (operator: any): operator is SimpleOperators =>
Object.keys(simpleOperatorMapping).includes(operator);

View File

@@ -1,48 +0,0 @@
import nock from "nock";
nock("https://api.airtable.com:443", { encodedQueryParams: true })
.post("/v0/appKYl1H4k9g73sBT/posts/", {
fields: {
title: "foo",
content: "bar",
status: "published",
category: ["recDBRJljBDFH4rIh"],
},
})
.query({})
.reply(
200,
[
"1f8b0800000000000003158c3d0f82301400ffcb9bc5b4151d3aa2821227c3e4c750e8436a2a35e53118c27ff7b15eee6e02674143c4a63c16785126dbc622aff7b082d6a1b703e809c89147b6da10980f6468640edfb1f66ee8d0326c0ce12bc41fe8fb323b64d7d2bfb3437e4ae3b983270ba127ec89b3dac4470f33a3885cd9ca7d96b9124a266297a8b4921b2d85966a2d84b8c1fc0704ab8bf4a4000000",
],
[
"access-control-allow-headers",
"authorization,content-length,content-type,user-agent,x-airtable-application-id,x-airtable-user-agent,x-api-version,x-requested-with",
"access-control-allow-methods",
"DELETE,GET,OPTIONS,PATCH,POST,PUT",
"access-control-allow-origin",
"*",
"content-encoding",
"gzip",
"Content-Type",
"application/json; charset=utf-8",
"Date",
"Thu, 24 Jun 2021 13:10:12 GMT",
"Server",
"Tengine",
"Set-Cookie",
"brw=brwhuRDEqN6Ub31j3; path=/; expires=Fri, 24 Jun 2022 13:10:12 GMT; domain=.airtable.com; samesite=none; secure",
"Strict-Transport-Security",
"max-age=31536000; includeSubDomains; preload",
"Vary",
"Accept-Encoding",
"X-Content-Type-Options",
"nosniff",
"X-Frame-Options",
"DENY",
"Content-Length",
"160",
"Connection",
"Close",
],
);

View File

@@ -1,26 +0,0 @@
import dataProvider from "../../src/index";
import "./index.mock";
describe("create", () => {
it("correct response", async () => {
const response = await dataProvider(
"keywoytODSr6xAqfg",
"appKYl1H4k9g73sBT",
).create({
resource: "posts",
variables: {
title: "foo",
content: "bar",
status: "published",
category: ["recDBRJljBDFH4rIh"],
},
});
const { data } = response;
expect(data["title"]).toEqual("foo");
expect(data["status"]).toEqual("published");
expect(data["category"]).toEqual(["recDBRJljBDFH4rIh"]);
expect(data["content"]).toEqual("bar\n");
});
});

View File

@@ -1,14 +0,0 @@
import dataProvider from "../../src/index";
describe("custom", () => {
it("correct get response", async () => {
try {
await dataProvider("keywoytODSr6xAqfg", "appKYl1H4k9g73sBT")
.custom!({ url: "users", method: "get" });
} catch (error) {
expect(error).toEqual(
Error("Not implemented on refine-airtable data provider."),
);
}
});
});

View File

@@ -1,41 +0,0 @@
import nock from "nock";
nock("https://api.airtable.com:443", { encodedQueryParams: true })
.delete("/v0/appKYl1H4k9g73sBT/posts")
.query({ "records%5B%5D": "recdgFXue7JnGD90w" })
.reply(
200,
[
"1f8b0800000000000003ab562a4a4dce2f4a2956b28aae564a49cd492d494d51b22a292a4dd551ca04b240f229e96e11a5a9e65e79ee2e9606e54ab5b1b5002d0259eb37000000",
],
[
"access-control-allow-headers",
"authorization,content-length,content-type,user-agent,x-airtable-application-id,x-airtable-user-agent,x-api-version,x-requested-with",
"access-control-allow-methods",
"DELETE,GET,OPTIONS,PATCH,POST,PUT",
"access-control-allow-origin",
"*",
"content-encoding",
"gzip",
"Content-Type",
"application/json; charset=utf-8",
"Date",
"Thu, 24 Jun 2021 13:17:00 GMT",
"Server",
"Tengine",
"Set-Cookie",
"brw=brwTjdQAZbqbk0xGk; path=/; expires=Fri, 24 Jun 2022 13:17:00 GMT; domain=.airtable.com; samesite=none; secure",
"Strict-Transport-Security",
"max-age=31536000; includeSubDomains; preload",
"Vary",
"Accept-Encoding",
"X-Content-Type-Options",
"nosniff",
"X-Frame-Options",
"DENY",
"Content-Length",
"71",
"Connection",
"Close",
],
);

View File

@@ -1,15 +0,0 @@
import dataProvider from "../../src/index";
import "./index.mock";
describe("deleteMany", () => {
it("correct response", async () => {
const response = await dataProvider(
"keywoytODSr6xAqfg",
"appKYl1H4k9g73sBT",
).deleteMany!({ resource: "posts", ids: ["recdgFXue7JnGD90w"] });
const { data } = response;
expect(data).not.toBeNull();
});
});

View File

@@ -1,41 +0,0 @@
import nock from "nock";
nock("https://api.airtable.com:443", { encodedQueryParams: true })
.delete("/v0/appKYl1H4k9g73sBT/posts/recJEGeL2aB5rGFbC")
.query({})
.reply(
200,
[
"1f8b0800000000000003ab564a49cd492d494d51b22a292a4dd551ca04b2948a5293bd5cdd537d8c129d4c8bdcdd929c956a016e8d991b29000000",
],
[
"access-control-allow-headers",
"authorization,content-length,content-type,user-agent,x-airtable-application-id,x-airtable-user-agent,x-api-version,x-requested-with",
"access-control-allow-methods",
"DELETE,GET,OPTIONS,PATCH,POST,PUT",
"access-control-allow-origin",
"*",
"content-encoding",
"gzip",
"Content-Type",
"application/json; charset=utf-8",
"Date",
"Thu, 24 Jun 2021 13:19:14 GMT",
"Server",
"Tengine",
"Set-Cookie",
"brw=brwInLaPzl4WP7sXu; path=/; expires=Fri, 24 Jun 2022 13:19:13 GMT; domain=.airtable.com; samesite=none; secure",
"Strict-Transport-Security",
"max-age=31536000; includeSubDomains; preload",
"Vary",
"Accept-Encoding",
"X-Content-Type-Options",
"nosniff",
"X-Frame-Options",
"DENY",
"Content-Length",
"59",
"Connection",
"Close",
],
);

View File

@@ -1,15 +0,0 @@
import dataProvider from "../../src/index";
import "./index.mock";
describe("deleteOne", () => {
it("correct response", async () => {
const response = await dataProvider(
"keywoytODSr6xAqfg",
"appKYl1H4k9g73sBT",
).deleteOne({ resource: "posts", id: "recJEGeL2aB5rGFbC" });
const { data } = response;
expect(data).not.toBeNull();
});
});

View File

@@ -1,150 +0,0 @@
import nock from "nock";
import url from "url";
const commonHeaders = [
"access-control-allow-headers",
"authorization,content-length,content-type,user-agent,x-airtable-application-id,x-airtable-user-agent,x-api-version,x-requested-with",
"access-control-allow-methods",
"DELETE,GET,OPTIONS,PATCH,POST,PUT",
"access-control-allow-origin",
"*",
"airtable-uncompressed-content-length",
"380",
"Content-Type",
"application/json; charset=utf-8",
"Date",
"Thu, 24 Jun 2021 12:24:32 GMT",
"Server",
"Tengine",
"Set-Cookie",
"brw=brwHislGvzT3Ws3Yf; path=/; expires=Fri, 24 Jun 2022 12:24:32 GMT; domain=.airtable.com; samesite=none; secure",
"Strict-Transport-Security",
"max-age=31536000; includeSubDomains; preload",
"Vary",
"Accept-Encoding",
"X-Content-Type-Options",
"nosniff",
"X-Frame-Options",
"DENY",
"Content-Length",
"233",
"Connection",
"Close",
];
nock("https://api.airtable.com:443", { encodedQueryParams: true })
.persist()
.get("/v0/appKYl1H4k9g73sBT/posts")
.query((query) => {
if (query.pageSize !== "100") return false;
if (query.filterByFormula === undefined) return false;
return true;
})
.reply(
200,
function () {
const parsed = new url.URL(this.req.path, "http://example.com");
const query = parsed.searchParams.get("filterByFormula");
return JSON.stringify({
offset: 0,
records: [
{
fields: {
query,
},
},
],
});
},
commonHeaders,
);
nock("https://api.airtable.com:443", { encodedQueryParams: true })
.get("/v0/appKYl1H4k9g73sBT/posts")
.query({ pageSize: "100" })
.reply(
200,
[
"1f8b0800000000000003954fc18ac23014fc157dc7a292562bdaa3c86a570f2215c5ad87da3cd7484cd634825aecb7fb82a0c74598c3639899375382c15c1b5e40f45382e01039a23fdaaea637dee517d58925346027503a4d09565889a41aa394bab6d446f25abb4e923cb3f8abcd95825cc47030ff9687c1f06bdc31f11e360d286c66cf94017fe7ad14c51eb9736965515962b38213525555cf8b5055a94a95e7bd88ccf3520577b219a4773c1147d7256081df64dda61f26be1f056114f65a8cb13529df9ba693b9d027b14bcc6c11dffedbf4d9228307cca9cf27d536f7073da8e6fb7c010000",
],
[
"access-control-allow-headers",
"authorization,content-length,content-type,user-agent,x-airtable-application-id,x-airtable-user-agent,x-api-version,x-requested-with",
"access-control-allow-methods",
"DELETE,GET,OPTIONS,PATCH,POST,PUT",
"access-control-allow-origin",
"*",
"airtable-uncompressed-content-length",
"380",
"content-encoding",
"gzip",
"Content-Type",
"application/json; charset=utf-8",
"Date",
"Thu, 24 Jun 2021 12:24:32 GMT",
"Server",
"Tengine",
"Set-Cookie",
"brw=brwHislGvzT3Ws3Yf; path=/; expires=Fri, 24 Jun 2022 12:24:32 GMT; domain=.airtable.com; samesite=none; secure",
"Strict-Transport-Security",
"max-age=31536000; includeSubDomains; preload",
"Vary",
"Accept-Encoding",
"X-Content-Type-Options",
"nosniff",
"X-Frame-Options",
"DENY",
"Content-Length",
"233",
"Connection",
"Close",
],
);
nock("https://api.airtable.com:443", { encodedQueryParams: true })
.get("/v0/appKYl1H4k9g73sBT/posts")
.query({
pageSize: "100",
"sort%5B0%5D%5Bfield%5D": "title",
"sort%5B0%5D%5Bdirection%5D": "desc",
})
.reply(
200,
[
"1f8b0800000000000003958f416bc2401085ff8ace31a86ca211cd518235d64391144b1b0f4976ac2beb6ebbbb426b30bfdd490bf59243857718debc6f785381c1521b6e217aab4070881a63f5b816fa53ec52f3f49c9ca1073b81b2c954605dee4ef62776c0d221a76d993b7cd7e69b6e34743c5b2fe56116cf172393ec61db03279c44621628a5ee6cb491bc0b17020d12ca53716cb6010bfc3e1bf7fd30f5fd2808a37032608cbd52f2566dfa50bcacce7cccbfd42891edd53e4e851476ffbf6ea5560e95232cb79c94a9bafe9d48759da94c79de9f917b5ea6a0f5a3cef0ae9fb6972ba8a00e5b7c010000",
],
[
"access-control-allow-headers",
"authorization,content-length,content-type,user-agent,x-airtable-application-id,x-airtable-user-agent,x-api-version,x-requested-with",
"access-control-allow-methods",
"DELETE,GET,OPTIONS,PATCH,POST,PUT",
"access-control-allow-origin",
"*",
"airtable-uncompressed-content-length",
"380",
"content-encoding",
"gzip",
"Content-Type",
"application/json; charset=utf-8",
"Date",
"Thu, 24 Jun 2021 13:07:26 GMT",
"Server",
"Tengine",
"Set-Cookie",
"brw=brw0sykMWa9glzNWF; path=/; expires=Fri, 24 Jun 2022 13:07:25 GMT; domain=.airtable.com; samesite=none; secure",
"Strict-Transport-Security",
"max-age=31536000; includeSubDomains; preload",
"Vary",
"Accept-Encoding",
"X-Content-Type-Options",
"nosniff",
"X-Frame-Options",
"DENY",
"Content-Length",
"237",
"Connection",
"Close",
],
);

View File

@@ -1,444 +0,0 @@
import { ConditionalFilter } from "@refinedev/core";
import dataProvider from "../../src/index";
import "./index.mock";
describe("getList", () => {
it("correct response", async () => {
const response = await dataProvider(
"keywoytODSr6xAqfg",
"appKYl1H4k9g73sBT",
).getList({
resource: "posts",
});
expect(response.data[0]["id"]).toBe("rec9GbXLzd6dxn4Il");
expect(response.data[0]["title"]).toBe("Hello World 3!");
expect(response.total).toBe(2);
});
it("correct sorting response", async () => {
const response = await dataProvider(
"keywoytODSr6xAqfg",
"appKYl1H4k9g73sBT",
).getList({
resource: "posts",
sorters: [
{
field: "title",
order: "desc",
},
],
});
expect(response.data[0]["id"]).toBe("recLKRioqifTrPUIz");
expect(response.data[0]["title"]).toBe("Hello World!");
expect(response.total).toBe(2);
});
it("correct equals filter for strings", async () => {
const filter = {
operator: "eq",
field: "title",
value: "Hello World!",
} as const;
const response = await dataProvider(
"keywoytODSr6xAqfg",
"appKYl1H4k9g73sBT",
).getList({
resource: "posts",
filters: [filter],
});
expect(response.total).toBe(1);
// {field} must equal exactly string
expect(response.data[0]["query"]).toBe('AND({title}="Hello World!")');
});
it("correct equals filter for numbers", async () => {
const filter = {
operator: "eq",
field: "age",
value: 100,
} as const;
const response = await dataProvider(
"keywoytODSr6xAqfg",
"appKYl1H4k9g73sBT",
).getList({
resource: "posts",
filters: [filter],
});
expect(response.total).toBe(1);
// {field} must equal exactly number
expect(response.data[0]["query"]).toBe("AND({age}=100)");
});
it("correct not equals filter for strings", async () => {
const filter = {
operator: "ne",
field: "title",
value: "Hello World!",
} as const;
const response = await dataProvider(
"keywoytODSr6xAqfg",
"appKYl1H4k9g73sBT",
).getList({
resource: "posts",
filters: [filter],
});
expect(response.total).toBe(1);
// {field} must not equal exactly string
expect(response.data[0]["query"]).toBe('AND({title}!="Hello World!")');
});
it("correct not equals filter for numbers", async () => {
const filter = {
operator: "ne",
field: "age",
value: 100,
} as const;
const response = await dataProvider(
"keywoytODSr6xAqfg",
"appKYl1H4k9g73sBT",
).getList({
resource: "posts",
filters: [filter],
});
expect(response.total).toBe(1);
// {field} must not equal exactly number
expect(response.data[0]["query"]).toBe("AND({age}!=100)");
});
it("correct less than filter", async () => {
const filter = {
operator: "lt",
field: "age",
value: 10,
} as const;
const response = await dataProvider(
"keywoytODSr6xAqfg",
"appKYl1H4k9g73sBT",
).getList({
resource: "posts",
filters: [filter],
});
expect(response.total).toBe(1);
// {field} must be less than value (as number)
expect(response.data[0]["query"]).toBe("AND({age}<10)");
});
it("correct less than or equal filter", async () => {
const filter = {
operator: "lte",
field: "age",
value: 10,
} as const;
const response = await dataProvider(
"keywoytODSr6xAqfg",
"appKYl1H4k9g73sBT",
).getList({
resource: "posts",
filters: [filter],
});
expect(response.total).toBe(1);
// {field} must be less than or equal value (as number)
expect(response.data[0]["query"]).toBe("AND({age}<=10)");
});
it("correct greater than filter", async () => {
const filter = {
operator: "gt",
field: "age",
value: 10,
} as const;
const response = await dataProvider(
"keywoytODSr6xAqfg",
"appKYl1H4k9g73sBT",
).getList({
resource: "posts",
filters: [filter],
});
expect(response.total).toBe(1);
// {field} must be greater than value (as number)
expect(response.data[0]["query"]).toBe("AND({age}>10)");
});
it("correct greater than or equal filter", async () => {
const filter = {
operator: "gte",
field: "age",
value: 10,
} as const;
const response = await dataProvider(
"keywoytODSr6xAqfg",
"appKYl1H4k9g73sBT",
).getList({
resource: "posts",
filters: [filter],
});
expect(response.total).toBe(1);
// {field} must be greater than or equal value (as number)
expect(response.data[0]["query"]).toBe("AND({age}>=10)");
});
it("correct contains filter", async () => {
const filter = {
operator: "containss",
field: "title",
value: "Hello",
} as const;
const response = await dataProvider(
"keywoytODSr6xAqfg",
"appKYl1H4k9g73sBT",
).getList({
resource: "posts",
filters: [filter],
});
expect(response.total).toBe(1);
// must find string in {field} - FIND returns non-zero value
expect(response.data[0]["query"]).toBe('AND(FIND("Hello",{title})!=0)');
});
it("correct not contains filter", async () => {
const filter = {
operator: "ncontainss",
field: "title",
value: "Hello",
} as const;
const response = await dataProvider(
"keywoytODSr6xAqfg",
"appKYl1H4k9g73sBT",
).getList({
resource: "posts",
filters: [filter],
});
expect(response.total).toBe(1);
// must not find string in {field} - FIND returns zero
expect(response.data[0]["query"]).toBe('AND(FIND("Hello",{title})=0)');
});
it("correct case-insensitive contains filter", async () => {
const filter = {
operator: "contains",
field: "title",
value: "Hello",
} as const;
const response = await dataProvider(
"keywoytODSr6xAqfg",
"appKYl1H4k9g73sBT",
).getList({
resource: "posts",
filters: [filter],
});
expect(response.total).toBe(1);
// must find lower-cased string in lower-cased {field} - lower-casing both values makes it case-insensitive
expect(response.data[0]["query"]).toBe(
'AND(FIND(LOWER("Hello"),LOWER({title}))!=0)',
);
});
it("correct case-insensitive not contains filter", async () => {
const filter = {
operator: "ncontains",
field: "title",
value: "Hello",
} as const;
const response = await dataProvider(
"keywoytODSr6xAqfg",
"appKYl1H4k9g73sBT",
).getList({
resource: "posts",
filters: [filter],
});
expect(response.total).toBe(1);
// must not find lower-cased string in lower-cased {field} - lower-casing both values makes it case-insensitive
expect(response.data[0]["query"]).toBe(
'AND(FIND(LOWER("Hello"),LOWER({title}))=0)',
);
});
it("correct truthy null filter", async () => {
const filter = {
operator: "null",
field: "title",
value: undefined,
} as const;
const response = await dataProvider(
"keywoytODSr6xAqfg",
"appKYl1H4k9g73sBT",
).getList({
resource: "posts",
filters: [filter],
});
expect(response.total).toBe(1);
// {field} must be null (blank)
expect(response.data[0]["query"]).toBe("AND({title}=BLANK())");
});
it("correct falsy null filter", async () => {
const filter = {
operator: "nnull",
field: "title",
value: undefined,
} as const;
const response = await dataProvider(
"keywoytODSr6xAqfg",
"appKYl1H4k9g73sBT",
).getList({
resource: "posts",
filters: [filter],
});
expect(response.total).toBe(1);
// {field} must not be null (blank)
expect(response.data[0]["query"]).toBe("AND({title}!=BLANK())");
});
it.each(["between", "nbetween"] as const)(
"fails for %s filter",
async (operator) => {
const filter = {
operator,
field: "age",
value: [10, 15],
} as const;
await expect(() => {
return dataProvider(
"keywoytODSr6xAqfg",
"appKYl1H4k9g73sBT",
).getList({
resource: "posts",
filters: [filter],
});
}).rejects.toThrow(
`Operator ${operator} is not supported for the Airtable data provider`,
);
},
);
it.each(["in", "nin"] as const)("fails for %s filter", async (operator) => {
const filter = {
operator,
field: "posts",
value: ["uuid-1", "uuid-2"],
} as const;
await expect(() => {
return dataProvider(
"keywoytODSr6xAqfg",
"appKYl1H4k9g73sBT",
).getList({
resource: "posts",
filters: [filter],
});
}).rejects.toThrow(
`Operator ${operator} is not supported for the Airtable data provider`,
);
});
it("correct 'or' conditional filter", async () => {
const filter = {
operator: "or",
value: [
{
field: "title",
operator: "eq",
value: "Silver Bullet",
},
{
field: "title",
operator: "ne",
value: "The Mythical Man Month",
},
],
} as ConditionalFilter;
const response = await dataProvider(
"keywoytODSr6xAqfg",
"appKYl1H4k9g73sBT",
).getList({
resource: "posts",
filters: [filter],
});
expect(response.total).toBe(1);
// {field} must either be Silver Bullet or must not be Mythical Man Month
expect(response.data[0]["query"]).toBe(
'AND(OR({title}="Silver Bullet",{title}!="The Mythical Man Month"))',
);
});
it("correct compound 'or' conditional filter", async () => {
const filters = [
{
operator: "or",
value: [
{
field: "title",
operator: "eq",
value: "Silver Bullet",
},
{
field: "title",
operator: "ne",
value: "The Mythical Man Month",
},
],
},
{
operator: "or",
value: [
{
field: "age",
operator: "gt",
value: 15,
},
{
field: "age",
operator: "lt",
value: 25,
},
],
},
] as ConditionalFilter[];
const response = await dataProvider(
"keywoytODSr6xAqfg",
"appKYl1H4k9g73sBT",
).getList({
resource: "posts",
filters: filters,
});
expect(response.total).toBe(1);
expect(response.data[0]["query"]).toBe(
'AND(OR({title}="Silver Bullet",{title}!="The Mythical Man Month"),OR({age}>15,{age}<25))',
);
});
});

View File

@@ -1,43 +0,0 @@
import nock from "nock";
nock("https://api.airtable.com:443", { encodedQueryParams: true })
.get("/v0/appKYl1H4k9g73sBT/posts")
.query({ pageSize: "100" })
.reply(
200,
[
"1f8b080000000000000395905d6b83301486ff4a974b69875a959acb526aed1c88d875747a114d5c53b2a48be9585bf4b72f6eeca3e0608373111e5e4e9ef79c8124a590b806f0e10c2806b0039302c55e54851b278d571118828a12d665ce4051c5884e5542685e2ba40e9a83fda160b4de12ac6129b8225c695a2099f18e20451e853cea4fbaf577c151be24cbc05fdfeed51ce48d4e48a23338a54fdd72dbb4ad91e98d6c27b5c6d0f4a133b9364d73039ae1b7a41f14f7d1097bf8953b21bb90ecd7ba94984d9325db4d67f38523c32dc87f7aa31aebc978db7ebcf4b46dc6336e185f0019c67bb7cf832c086362b01692e1c1f80afcdac97253cb82b60bdd9e4ed14d42c533ad5219afc2537f274976a4547fabd423f72fb5bc7903b0079a9c21020000",
],
[
"access-control-allow-headers",
"authorization,content-length,content-type,user-agent,x-airtable-application-id,x-airtable-user-agent,x-api-version,x-requested-with",
"access-control-allow-methods",
"DELETE,GET,OPTIONS,PATCH,POST,PUT",
"access-control-allow-origin",
"*",
"airtable-uncompressed-content-length",
"545",
"content-encoding",
"gzip",
"Content-Type",
"application/json; charset=utf-8",
"Date",
"Thu, 24 Jun 2021 13:20:40 GMT",
"Server",
"Tengine",
"Set-Cookie",
"brw=brwNd7NWRhWftbS0Q; path=/; expires=Fri, 24 Jun 2022 13:20:40 GMT; domain=.airtable.com; samesite=none; secure",
"Strict-Transport-Security",
"max-age=31536000; includeSubDomains; preload",
"Vary",
"Accept-Encoding",
"X-Content-Type-Options",
"nosniff",
"X-Frame-Options",
"DENY",
"Content-Length",
"294",
"Connection",
"Close",
],
);

View File

@@ -1,20 +0,0 @@
import dataProvider from "../../src/index";
import "./index.mock";
describe("getMany", () => {
it("correct response", async () => {
const response = await dataProvider(
"keywoytODSr6xAqfg",
"appKYl1H4k9g73sBT",
).getMany!({
resource: "posts",
ids: ["recLKRioqifTrPUIz", "rec9GbXLzd6dxn4Il"],
});
const { data } = response;
expect(data[0]["id"]).toBe("rec9GbXLzd6dxn4Il");
expect(data[1]["id"]).toBe("recLKRioqifTrPUIz");
expect(response.data.length).toBe(2);
});
});

View File

@@ -1,43 +0,0 @@
import nock from "nock";
nock("https://api.airtable.com:443", { encodedQueryParams: true })
.get("/v0/appKYl1H4k9g73sBT/posts/recLKRioqifTrPUIz")
.query({})
.reply(
200,
[
"1f8b08000000000000031dcb410bc2201880e1bf52df790b958cf038c6d8aa430c23283a0cfd560e43523bd4d87fcf757edf6704a341804775d8b7c6bd4c2ffdf1d47c2183dea0d501c4082176f11dfedb802aa24e557511efce7f405c675d16edce0e4559d56bdf3ce0964134d16232355aeb1667e7ad5ec294a0c744b534cfb932c2684e3639e59252c1b8e0db1521e402d30fb10f929e9a000000",
],
[
"access-control-allow-headers",
"authorization,content-length,content-type,user-agent,x-airtable-application-id,x-airtable-user-agent,x-api-version,x-requested-with",
"access-control-allow-methods",
"DELETE,GET,OPTIONS,PATCH,POST,PUT",
"access-control-allow-origin",
"*",
"airtable-uncompressed-content-length",
"154",
"content-encoding",
"gzip",
"Content-Type",
"application/json; charset=utf-8",
"Date",
"Thu, 24 Jun 2021 13:21:53 GMT",
"Server",
"Tengine",
"Set-Cookie",
"brw=brwQBAba4kMeu0MpF; path=/; expires=Fri, 24 Jun 2022 13:21:53 GMT; domain=.airtable.com; samesite=none; secure",
"Strict-Transport-Security",
"max-age=31536000; includeSubDomains; preload",
"Vary",
"Accept-Encoding",
"X-Content-Type-Options",
"nosniff",
"X-Frame-Options",
"DENY",
"Content-Length",
"156",
"Connection",
"Close",
],
);

View File

@@ -1,17 +0,0 @@
import dataProvider from "../../src/index";
import "./index.mock";
describe("getOne", () => {
it("correct response", async () => {
const response = await dataProvider(
"keywoytODSr6xAqfg",
"appKYl1H4k9g73sBT",
).getOne({ resource: "posts", id: "recLKRioqifTrPUIz" });
const { data } = response;
expect(data.title).toBe("Hello World!");
expect(data.status).toBe("rejected");
expect(data.category).toEqual(["recDBRJljBDFH4rIh"]);
});
});

View File

@@ -1,11 +0,0 @@
const fetch = require("node-fetch");
const nock = require("nock");
global.fetch = window.fetch = fetch;
global.Request = window.Request = fetch.Request;
global.Response = window.Response = fetch.Response;
afterAll(() => {
nock.cleanAll();
nock.restore();
});

View File

@@ -1,43 +0,0 @@
import nock from "nock";
nock("https://api.airtable.com:443", { encodedQueryParams: true })
.patch("/v0/appKYl1H4k9g73sBT/posts/recLKRioqifTrPUIz", {
fields: { title: "Hello World!!" },
})
.query({})
.reply(
200,
[
"1f8b08000000000000031dcb410bc2201880e1bfd2bef3162a19e1718cd8aa430c23283a0cfd560e43523bd4d87fcf757edf6704a341804775d8b7c6bd4c2ffdf1d47c2187dea0d501c4082176f11dfedb802aa24e557511efce7f405c675d95edce0e65b5ad57be79c02d8768a2c5646ab4d62dcece5b9d653025e931592dcd73ce8c305a907541b9a454302ef8664908b9c0f4030447c06c9b000000",
],
[
"access-control-allow-headers",
"authorization,content-length,content-type,user-agent,x-airtable-application-id,x-airtable-user-agent,x-api-version,x-requested-with",
"access-control-allow-methods",
"DELETE,GET,OPTIONS,PATCH,POST,PUT",
"access-control-allow-origin",
"*",
"content-encoding",
"gzip",
"Content-Type",
"application/json; charset=utf-8",
"Date",
"Thu, 24 Jun 2021 13:24:42 GMT",
"Server",
"Tengine",
"Set-Cookie",
"brw=brwQrvJXnX0I6wkCt; path=/; expires=Fri, 24 Jun 2022 13:24:42 GMT; domain=.airtable.com; samesite=none; secure",
"Strict-Transport-Security",
"max-age=31536000; includeSubDomains; preload",
"Vary",
"Accept-Encoding",
"X-Content-Type-Options",
"nosniff",
"X-Frame-Options",
"DENY",
"Content-Length",
"157",
"Connection",
"Close",
],
);

View File

@@ -1,21 +0,0 @@
import dataProvider from "../../src/index";
import "./index.mock";
describe("update", () => {
it("correct response", async () => {
const response = await dataProvider(
"keywoytODSr6xAqfg",
"appKYl1H4k9g73sBT",
).update({
resource: "posts",
id: "recLKRioqifTrPUIz",
variables: {
title: "Hello World!!",
},
});
const { data } = response;
expect(data["title"]).toBe("Hello World!!");
});
});

View File

@@ -1,46 +0,0 @@
import nock from "nock";
nock("https://api.airtable.com:443", { encodedQueryParams: true })
.patch("/v0/appKYl1H4k9g73sBT/posts/", {
records: [
{ id: "recLKRioqifTrPUIz", fields: { title: "Hello World!!!" } },
{ id: "rec9GbXLzd6dxn4Il", fields: { title: "Hello World!!!" } },
],
})
.query({})
.reply(
200,
[
"1f8b0800000000000003ad8f416bc2401085ff8a996350d9042336471135ad872229169b1c6276d49575577757680de6b73b69412f3d7810e630bcf7bee14d05064b6db885f8ab02c1216e84d9db5ce8a358a7e6fd2339431bd6026593a9c0bac29dec6f6c87a5434e6e5938dc68f343371a7a349cbfcadd70349ef64cb285bc0d4e3889c44c514add5a6823b9e7797021d420c13c15fbc60f59187458bf13446910c4611447832e636c49c97bb997c9ea7376e67dfead7a89fcbfdce1b492c26e1f6b576ae55039c20acb693255d77f1b4d5d672a53be7f130adfcf143ce3a7fc720554f78d147e010000",
],
[
"access-control-allow-headers",
"authorization,content-length,content-type,user-agent,x-airtable-application-id,x-airtable-user-agent,x-api-version,x-requested-with",
"access-control-allow-methods",
"DELETE,GET,OPTIONS,PATCH,POST,PUT",
"access-control-allow-origin",
"*",
"content-encoding",
"gzip",
"Content-Type",
"application/json; charset=utf-8",
"Date",
"Thu, 24 Jun 2021 13:26:53 GMT",
"Server",
"Tengine",
"Set-Cookie",
"brw=brwPAe5xxAm5wIYu2; path=/; expires=Fri, 24 Jun 2022 13:26:53 GMT; domain=.airtable.com; samesite=none; secure",
"Strict-Transport-Security",
"max-age=31536000; includeSubDomains; preload",
"Vary",
"Accept-Encoding",
"X-Content-Type-Options",
"nosniff",
"X-Frame-Options",
"DENY",
"Content-Length",
"235",
"Connection",
"Close",
],
);

View File

@@ -1,22 +0,0 @@
import dataProvider from "../../src/index";
import "./index.mock";
describe("updateMany", () => {
it("correct response", async () => {
const response = await dataProvider(
"keywoytODSr6xAqfg",
"appKYl1H4k9g73sBT",
).updateMany!({
resource: "posts",
ids: ["recLKRioqifTrPUIz", "rec9GbXLzd6dxn4Il"],
variables: {
title: "Hello World!!!",
},
});
const { data } = response;
expect(data[0]["title"]).toBe("Hello World!!!");
expect(data[1]["title"]).toBe("Hello World!!!");
});
});

View File

@@ -1,33 +0,0 @@
import { CrudFilters } from "@refinedev/core";
import { generateFilter } from "../../src/utils";
describe("generateFilter", () => {
it("should return undefined when no filters are provided", () => {
expect(generateFilter()).toBeUndefined();
});
it("should return a filter formula when filters are provided", () => {
const filters: CrudFilters = [
{ field: "name", operator: "eq", value: "John" },
{ field: "age", operator: "gte", value: 30 },
];
const expected = 'AND({name}="John",{age}>=30)';
expect(generateFilter(filters)).toBe(expected);
});
it("should return a complex filter formula with nested filters", () => {
const filters: CrudFilters = [
{
operator: "or",
value: [
{ field: "name", operator: "eq", value: "John" },
{ field: "name", operator: "eq", value: "Jane" },
],
},
{ field: "age", operator: "gte", value: 30 },
];
const expected = 'AND(OR({name}="John",{name}="Jane"),{age}>=30)';
expect(generateFilter(filters)).toBe(expected);
});
});

View File

@@ -1,44 +0,0 @@
import { CrudFilters } from "@refinedev/core";
import { generateFilterFormula } from "../../src/utils";
describe("generateFilterFormula", () => {
it("should return an empty array when no filters are provided", () => {
expect(generateFilterFormula([])).toEqual([]);
});
it("should return a formula array when filters are provided", () => {
const filters: CrudFilters = [
{ field: "name", operator: "eq", value: "John" },
{ field: "age", operator: "gte", value: 30 },
];
const expected = [
["=", { field: "name" }, "John"],
[">=", { field: "age" }, 30],
];
expect(generateFilterFormula(filters)).toEqual(expected);
});
it("should return a complex formula array with nested filters", () => {
const filters: CrudFilters = [
{
operator: "or",
value: [
{ field: "name", operator: "eq", value: "John" },
{ field: "name", operator: "eq", value: "Jane" },
],
},
{ field: "age", operator: "gte", value: 30 },
];
const expected = [
[
"OR",
["=", { field: "name" }, "John"],
["=", { field: "name" }, "Jane"],
],
[">=", { field: "age" }, 30],
];
expect(generateFilterFormula(filters)).toEqual(expected);
});
});

View File

@@ -1,58 +0,0 @@
import { CrudFilter } from "@refinedev/core";
import { generateLogicalFilterFormula } from "../../src/utils";
import { LogicalFilter } from "@refinedev/core";
describe("generateLogicalFilterFormula", () => {
it("should generate a formula for simple operators", () => {
const filter: CrudFilter = {
field: "age",
operator: "gte",
value: 30,
};
const expected = [">=", { field: "age" }, 30];
expect(generateLogicalFilterFormula(filter)).toEqual(expected);
});
it("should generate a formula for contains operators", () => {
const filter: CrudFilter = {
field: "name",
operator: "contains",
value: "John",
};
const expected = [
"!=",
["FIND", ["LOWER", "John"], ["LOWER", { field: "name" }]],
0,
];
expect(generateLogicalFilterFormula(filter)).toEqual(expected);
});
it("should generate a formula for null operators", () => {
const filter = { field: "email", operator: "null" } as LogicalFilter;
const expected = ["=", { field: "email" }, ["BLANK"]];
expect(generateLogicalFilterFormula(filter)).toEqual(expected);
});
it("should generate a formula for nnull operators", () => {
const filter = { field: "email", operator: "nnull" } as LogicalFilter;
const expected = ["!=", { field: "email" }, ["BLANK"]];
expect(generateLogicalFilterFormula(filter)).toEqual(expected);
});
it("should throw an error for unsupported operators", () => {
const filter = {
field: "age",
operator: "unsupported",
value: 30,
} as unknown as LogicalFilter;
expect(() => generateLogicalFilterFormula(filter)).toThrowError(
"Operator unsupported is not supported for the Airtable data provider",
);
});
});

View File

@@ -1,22 +0,0 @@
import { CrudSorting } from "@refinedev/core";
import { generateSort } from "../../src/utils";
describe("generateSort", () => {
it("should return undefined if no sorters are provided", () => {
expect(generateSort(undefined)).toBeUndefined();
});
it("should generate an array of sorting objects", () => {
const sorters: CrudSorting = [
{ field: "name", order: "asc" },
{ field: "age", order: "desc" },
];
const expected = [
{ field: "name", direction: "asc" },
{ field: "age", direction: "desc" },
];
expect(generateSort(sorters)).toEqual(expected);
});
});

View File

@@ -1,31 +0,0 @@
import { isContainssOperator, isContainsOperator } from "../../src/utils";
describe("Operators", () => {
describe("isContainssOperator", () => {
it("should return true if operator is containss", () => {
expect(isContainssOperator("containss")).toBe(true);
});
it("should return true if operator is ncontainss", () => {
expect(isContainssOperator("ncontainss")).toBe(true);
});
it("should return false if operator is not containss or ncontainss", () => {
expect(isContainssOperator("contains")).toBe(false);
});
});
describe("isContainsOperator", () => {
it("should return true if operator is contains", () => {
expect(isContainsOperator("contains")).toBe(true);
});
it("should return true if operator is ncontains", () => {
expect(isContainsOperator("ncontains")).toBe(true);
});
it("should return false if operator is not contains or ncontains", () => {
expect(isContainsOperator("containss")).toBe(false);
});
});
});

View File

@@ -1,30 +0,0 @@
import { isSimpleOperator, simpleOperatorMapping } from "../../src/utils";
describe("SimpleOperators", () => {
describe("isSimpleOperator", () => {
it("should return true if operator is a simple operator", () => {
expect(isSimpleOperator("eq")).toBe(true);
expect(isSimpleOperator("ne")).toBe(true);
expect(isSimpleOperator("lt")).toBe(true);
expect(isSimpleOperator("lte")).toBe(true);
expect(isSimpleOperator("gt")).toBe(true);
expect(isSimpleOperator("gte")).toBe(true);
});
it("should return false if operator is not a simple operator", () => {
expect(isSimpleOperator("contains")).toBe(false);
expect(isSimpleOperator("containss")).toBe(false);
});
});
describe("simpleOperatorMapping", () => {
it("should map simple operators to their corresponding Airtable symbols", () => {
expect(simpleOperatorMapping["eq"]).toBe("=");
expect(simpleOperatorMapping["ne"]).toBe("!=");
expect(simpleOperatorMapping["lt"]).toBe("<");
expect(simpleOperatorMapping["lte"]).toBe("<=");
expect(simpleOperatorMapping["gt"]).toBe(">");
expect(simpleOperatorMapping["gte"]).toBe(">=");
});
});
});

View File

@@ -1,21 +0,0 @@
{
"extends": "./tsconfig.json",
"exclude": [
"node_modules",
"dist",
"test",
"../test/**/*",
"**/*.spec.ts",
"**/*.test.ts",
"**/*.spec.tsx",
"**/*.test.tsx"
],
"compilerOptions": {
"outDir": "dist",
"declarationDir": "dist",
"declaration": true,
"emitDeclarationOnly": true,
"noEmit": false,
"declarationMap": true
}
}

View File

@@ -1,8 +0,0 @@
{
"include": ["src", "types", "refine.config.js"],
"extends": "../../tsconfig.build.json",
"compilerOptions": {
"rootDir": "./src",
"baseUrl": "."
}
}

View File

@@ -1,24 +0,0 @@
import { defineConfig } from "tsup";
import { NodeResolvePlugin } from "@esbuild-plugins/node-resolve";
export default defineConfig({
entry: ["src/index.ts"],
splitting: false,
sourcemap: true,
clean: false,
platform: "browser",
esbuildPlugins: [
NodeResolvePlugin({
extensions: [".js", "ts", "tsx", "jsx"],
onResolved: (resolved) => {
if (resolved.includes("node_modules")) {
return {
external: true,
};
}
return resolved;
},
}),
],
onSuccess: "tsc --project tsconfig.declarations.json",
});

View File

@@ -1,11 +0,0 @@
node_modules
.DS_Store
test
jest.config.js
**/*.spec.ts
**/*.spec.tsx
**/*.test.ts
**/*.test.tsx
tsup.config.ts
tsconfig.test.json
tsconfig.declarations.json

View File

@@ -1 +0,0 @@
legacy-peer-deps=true

File diff suppressed because it is too large Load Diff

View File

@@ -1,71 +0,0 @@
<div align="center" style="margin: 30px;">
<a href="https://refine.dev">
<img alt="refine logo" src="https://refine.ams3.cdn.digitaloceanspaces.com/readme/refine-readme-banner.png">
</a>
</div>
<br/>
<div align="center">
<a href="https://refine.dev">Home Page</a> |
<a href="https://discord.gg/refine">Discord</a> |
<a href="https://refine.dev/examples/">Examples</a> |
<a href="https://refine.dev/blog/">Blog</a> |
<a href="https://refine.dev/docs/">Documentation</a>
<br/>
<br/>
[![Discord](https://img.shields.io/discord/837692625737613362.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/refine)
[![Twitter Follow](https://img.shields.io/twitter/follow/refine_dev?style=social)](https://twitter.com/refine_dev)
<a href="https://www.producthunt.com/posts/refine-3?utm_source=badge-top-post-badge&utm_medium=badge&utm_souce=badge-refine&#0045;3" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/top-post-badge.svg?post_id=362220&theme=light&period=daily" alt="refine - 100&#0037;&#0032;open&#0032;source&#0032;React&#0032;framework&#0032;to&#0032;build&#0032;web&#0032;apps&#0032;3x&#0032;faster | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
</div>
<br/>
<div align="center">refine is an open-source, headless React framework for developers building enterprise internal tools, admin panels, dashboards, B2B applications.
<br/>
It eliminates repetitive tasks in CRUD operations and provides industry-standard solutions for critical project components like **authentication**, **access control**, **routing**, **networking**, **state management**, and **i18n**.
</div>
# Ant Design integration for refine
[Ant Design](https://ant.design/) is a React.js UI library that contains easy-to-use components that are useful for building interactive user interfaces.
[refine](https://refine.dev/) is **headless by design**, offering unlimited styling and customization options. Moreover, refine ships with ready-made integrations for [Ant Design](https://ant.design/), [Material UI](https://mui.com/material-ui/getting-started/overview/), [Mantine](https://mantine.dev/), and [Chakra UI](https://chakra-ui.com/) for convenience.
refine has connectors for 15+ backend services, including REST API, [GraphQL](https://graphql.org/), and popular services like [Airtable](https://www.airtable.com/), [Strapi](https://strapi.io/), [Supabase](https://supabase.com/), [Firebase](https://firebase.google.com/), and [NestJS](https://nestjs.com/).
## Installation & Usage
```
npm install @refinedev/antd antd
```
```tsx
import { ThemedLayoutV2 } from "@refinedev/antd";
import "@refinedev/antd/dist/reset.css";
const App = () => {
return (
<Refine
/* ... */
>
<ThemedLayoutV2>{/* ... */}</ThemedLayoutV2>
</Refine>
);
};
```
## Documentation
- For more detailed information and usage, refer to the [refine Ant Design documentation](https://refine.dev/docs/api-reference/antd/).
- [Refer to complete refine tutorial with Ant Design](https://refine.dev/docs/tutorial/introduction/select-framework/)
- [Refer to documentation for more info about refine](https://refine.dev/docs/).
- [Step up to refine tutorials](https://refine.dev/docs/tutorial/introduction/index/).

View File

@@ -1,31 +0,0 @@
const { pathsToModuleNameMapper } = require("ts-jest");
const { compilerOptions } = require("./tsconfig.json");
const paths = compilerOptions.paths ? compilerOptions.paths : {};
module.exports = {
preset: "ts-jest",
rootDir: "./",
testEnvironment: "jsdom",
setupFilesAfterEnv: ["<rootDir>/test/jest.setup.ts"],
testPathIgnorePatterns: ["<rootDir>/node_modules/"],
moduleNameMapper: {
...pathsToModuleNameMapper(paths, { prefix: "<rootDir>/" }),
"\\.css$": "identity-obj-proxy",
"^antd/es/": "antd/lib/",
"^.+\\.tsx?$": [
"ts-jest",
{
tsconfig: "<rootDir>/tsconfig.test.json",
},
],
},
displayName: "antd",
transform: {
"^.+\\.svg$": "<rootDir>/test/svgTransform.ts",
},
coveragePathIgnorePatterns: [
"<rootDir>/src/index.ts",
"<rootDir>/src/interfaces/",
],
};

View File

@@ -1,75 +0,0 @@
{
"name": "@refinedev/antd",
"version": "5.37.2",
"description": "refine is a React-based framework for building internal tools, rapidly. It ships with Ant Design System, an enterprise-level UI toolkit.",
"private": false,
"sideEffects": [
"*.css"
],
"main": "dist/index.js",
"module": "dist/esm/index.js",
"typings": "dist/index.d.ts",
"scripts": {
"start": "tsup --watch --format esm,cjs,iife --legacy-output",
"build": "tsup --format esm,cjs,iife --minify --legacy-output",
"test": "jest --passWithNoTests --runInBand",
"prepare": "npm run build",
"generate-theme": "npx @emeks/antd-custom-theme-generator -w --antd ../../node_modules/antd ./src/assets/styles/custom-theme.less ./src/assets/styles/styles.min.css"
},
"peerDependencies": {
"@refinedev/core": "^4.46.1",
"@types/react": "^17.0.0 || ^18.0.0",
"@types/react-dom": "^17.0.0 || ^18.0.0",
"antd": "^5.0.5",
"dayjs": "^1.10.7",
"react": "^17.0.0 || ^18.0.0",
"react-dom": "^17.0.0 || ^18.0.0"
},
"devDependencies": {
"@refinedev/cli": "^2.16.22",
"@refinedev/ui-tests": "^1.14.1",
"@refinedev/core": "^4.46.2",
"@esbuild-plugins/node-resolve": "^0.1.4",
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.1.1",
"@testing-library/react-hooks": "^8.0.0",
"@testing-library/user-event": "^14.1.1",
"@types/jest": "^29.2.4",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"@types/testing-library__jest-dom": "^5.14.3",
"esbuild-copy-static-files": "^0.1.0",
"esbuild-plugin-inline-image": "^0.0.8",
"identity-obj-proxy": "^3.0.0",
"jest": "^29.3.1",
"jest-environment-jsdom": "^29.3.1",
"postcss": "^8.1.4",
"react-router-dom": "^6.8.1",
"ts-jest": "^29.0.3",
"tsup": "^6.7.0",
"typescript": "^4.7.4"
},
"dependencies": {
"@ant-design/icons": "5.0.1",
"@ant-design/pro-layout": "7.17.12",
"@refinedev/ui-types": "^1.22.4",
"@tanstack/react-query": "^4.10.1",
"antd": "^5.0.5",
"dayjs": "^1.10.7",
"react-markdown": "^6.0.1",
"remark-gfm": "^1.0.0",
"sunflower-antd": "1.0.0-beta.3",
"tslib": "^2.3.1"
},
"author": "refine",
"license": "MIT",
"gitHead": "829f5a516f98c06f666d6be3e6e6099c75c07719",
"repository": {
"type": "git",
"url": "https://github.com/refinedev/refine.git",
"directory": "packages/antd"
},
"publishConfig": {
"access": "public"
}
}

View File

@@ -1,629 +0,0 @@
const { dirname, join } = require("path");
const {
getImports,
appendAfterImports,
getFileContent,
} = require("@refinedev/cli");
/** @type {import('@refinedev/cli').RefineConfig} */
module.exports = {
group: "UI Framework",
swizzle: {
items: [
{
group: "Buttons",
label: "ShowButton",
files: [
{
src: "./src/components/buttons/show/index.tsx",
dest: "./components/buttons/show.tsx",
},
],
},
{
group: "Buttons",
label: "CreateButton",
message: `
**\`Warning:\`**
This component is used in the below component. If you want to change it, you can run the **swizzle** command for the below component or you can use props to override the default buttons.
- <List/>
`,
files: [
{
src: "./src/components/buttons/create/index.tsx",
dest: "./components/buttons/create.tsx",
},
],
},
{
group: "Buttons",
label: "CloneButton",
files: [
{
src: "./src/components/buttons/clone/index.tsx",
dest: "./components/buttons/clone.tsx",
},
],
},
{
group: "Buttons",
label: "DeleteButton",
message: `
**\`Warning:\`**
This component is used in the below components. If you want to change it, you can run the **swizzle** command for the below components or you can use props to override the default buttons.
- <Edit/>
- <List/>
`,
files: [
{
src: "./src/components/buttons/delete/index.tsx",
dest: "./components/buttons/delete.tsx",
},
],
},
{
group: "Buttons",
label: "EditButton",
message: `
**\`Warning:\`**
This component is used in the below component. If you want to change it, you can run the **swizzle** command for the below component or you can use props to override the default buttons.
- <Show/>
`,
files: [
{
src: "./src/components/buttons/edit/index.tsx",
dest: "./components/buttons/edit.tsx",
},
],
},
{
group: "Buttons",
label: "ExportButton",
files: [
{
src: "./src/components/buttons/export/index.tsx",
dest: "./components/buttons/export.tsx",
},
],
},
{
group: "Buttons",
label: "ImportButton",
files: [
{
src: "./src/components/buttons/import/index.tsx",
dest: "./components/buttons/import.tsx",
},
],
},
{
group: "Buttons",
label: "ListButton",
message: `
**\`Warning:\`**
This component is used in the below components. If you want to change it, you can run the **swizzle** command for the below components or you can use props to override the default buttons.
- <Edit/>
- <Show/>
`,
files: [
{
src: "./src/components/buttons/list/index.tsx",
dest: "./components/buttons/list.tsx",
},
],
},
{
group: "Buttons",
label: "RefreshButton",
message: `
**\`Warning:\`**
This component is used in the below components. If you want to change it, you can run the **swizzle** command for the below components or you can use props to override the default buttons.
- <Edit/>
- <Show/>
`,
files: [
{
src: "./src/components/buttons/refresh/index.tsx",
dest: "./components/buttons/refresh.tsx",
},
],
},
{
group: "Buttons",
label: "SaveButton",
message: `
**\`Warning:\`**
This component is used in the below components. If you want to change it, you can run the **swizzle** command for the below components or you can use props to override the default buttons.
- <Create/>
- <Edit/>
`,
files: [
{
src: "./src/components/buttons/save/index.tsx",
dest: "./components/buttons/save.tsx",
},
],
},
{
group: "Basic Views",
label: "Create",
files: [
{
src: "./src/components/crud/create/index.tsx",
dest: "./components/crud/create.tsx",
},
],
},
{
group: "Basic Views",
label: "List",
files: [
{
src: "./src/components/crud/list/index.tsx",
dest: "./components/crud/list.tsx",
},
],
},
{
group: "Basic Views",
label: "Show",
files: [
{
src: "./src/components/crud/show/index.tsx",
dest: "./components/crud/show.tsx",
},
],
},
{
group: "Basic Views",
label: "Edit",
files: [
{
src: "./src/components/crud/edit/index.tsx",
dest: "./components/crud/edit.tsx",
},
],
},
{
group: "Fields",
label: "BooleanField",
files: [
{
src: "./src/components/fields/boolean/index.tsx",
dest: "./components/fields/boolean.tsx",
},
],
},
{
group: "Fields",
label: "DateField",
files: [
{
src: "./src/components/fields/date/index.tsx",
dest: "./components/fields/date.tsx",
},
],
},
{
group: "Fields",
label: "EmailField",
files: [
{
src: "./src/components/fields/email/index.tsx",
dest: "./components/fields/email.tsx",
},
],
},
{
group: "Fields",
label: "FileField",
files: [
{
src: "./src/components/fields/file/index.tsx",
dest: "./components/fields/file.tsx",
},
],
},
{
group: "Fields",
label: "ImageField",
files: [
{
src: "./src/components/fields/image/index.tsx",
dest: "./components/fields/image.tsx",
},
],
},
{
group: "Fields",
label: "MarkdownField",
files: [
{
src: "./src/components/fields/markdown/index.tsx",
dest: "./components/fields/markdown.tsx",
},
],
},
{
group: "Fields",
label: "NumberField",
files: [
{
src: "./src/components/fields/number/index.tsx",
dest: "./components/fields/number.tsx",
},
],
},
{
group: "Fields",
label: "TagField",
files: [
{
src: "./src/components/fields/tag/index.tsx",
dest: "./components/fields/tag.tsx",
},
],
},
{
group: "Fields",
label: "TextField",
files: [
{
src: "./src/components/fields/text/index.tsx",
dest: "./components/fields/text.tsx",
},
],
},
{
group: "Fields",
label: "UrlField",
files: [
{
src: "./src/components/fields/url/index.tsx",
dest: "./components/fields/url.tsx",
},
],
},
{
group: "Pages",
label: "ErrorPage",
message: `
**\`Info:\`**
If you want to see an example of error page in use, you can refer to the documentation at https://refine.dev/docs/packages/documentation/routers
`,
files: [
{
src: "./src/components/pages/error/index.tsx",
dest: "./components/pages/error.tsx",
transform: (content) => {
let newContent = content;
// for remove RefineErorrPageProps
const refineErrorPagePropsRegex =
/React\.FC<RefineErrorPageProps>/g;
newContent = newContent.replace(
refineErrorPagePropsRegex,
"React.FC",
);
return newContent;
},
},
],
},
{
group: "Pages",
label: "AuthPage",
message: `
**\`Info:\`**
If you want to see examples of authentication pages in use, you can refer to the documentation at https://refine.dev/docs/packages/documentation/routers
`,
files: [
{
src: "./src/components/pages/auth/index.tsx",
dest: "./components/pages/auth/index.tsx",
},
{
src: "./src/components/pages/auth/components/forgotPassword/index.tsx",
dest: "./components/pages/auth/components/forgotPassword.tsx",
transform: (content) => {
let newContent = content;
// for change style import path
const styleImportRegex = /"\.\.\/styles";/g;
newContent = newContent.replace(
styleImportRegex,
`"./styles";`,
);
return newContent;
},
},
{
src: "./src/components/pages/auth/components/login/index.tsx",
dest: "./components/pages/auth/components/login.tsx",
transform: (content) => {
let newContent = content;
// for change style import path
const styleImportRegex = /"\.\.\/styles";/g;
newContent = newContent.replace(
styleImportRegex,
`"./styles";`,
);
return newContent;
},
},
{
src: "./src/components/pages/auth/components/register/index.tsx",
dest: "./components/pages/auth/components/register.tsx",
transform: (content) => {
let newContent = content;
// for change style import path
const styleImportRegex = /"\.\.\/styles";/g;
newContent = newContent.replace(
styleImportRegex,
`"./styles";`,
);
return newContent;
},
},
{
src: "./src/components/pages/auth/components/updatePassword/index.tsx",
dest: "./components/pages/auth/components/updatePassword.tsx",
transform: (content) => {
let newContent = content;
// for change style import path
const styleImportRegex = /"\.\.\/styles";/g;
newContent = newContent.replace(
styleImportRegex,
`"./styles";`,
);
return newContent;
},
},
{
src: "./src/components/pages/auth/components/index.tsx",
dest: "./components/pages/auth/components/index.tsx",
},
{
src: "./src/components/pages/auth/components/styles.ts",
dest: "./components/pages/auth/components/styles.ts",
},
],
},
{
group: "Other",
label: "Breadcrumb",
message: `
**\`Warning:\`**
This component is used in the below components. If you want to change it, you can use props to override the default breadcrumb or you can manage globally with the **options** prop to the **<Refine/>** component.
- <Edit/>
- <List/>
- <Show/>
- <Create/>
**\`Passing Breadcrumb Globally:\`**
\`\`\`
// title: App.tsx
import { Breadcrumb } from "components/breadcrumb";
const App = () => {
return (
<Refine
options={{
breadcrumb: <Breadcrumb />
/* ... */
}}
/* ... */
/>
);
}
\`\`\`
`,
files: [
{
src: "./src/components/breadcrumb/index.tsx",
dest: "./components/breadcrumb.tsx",
transform: (content) => {
let newContent = content;
// for remove type export
const breadcrumbPropsExportRegex =
/export type BreadcrumbProps = RefineBreadcrumbProps<AntdBreadcrumbProps>;?/g;
newContent = newContent.replace(
breadcrumbPropsExportRegex,
`import { BreadcrumbProps } from "@refinedev/antd";`,
);
// change the breadcrumb import path
const breadcrumbImportRegex =
/BreadcrumbProps as AntdBreadcrumbProps,/g;
newContent = newContent.replace(
breadcrumbImportRegex,
"",
);
return newContent;
},
},
],
},
{
group: "Other",
label: "ThemedLayoutV2",
message: `
**\`Warning:\`**
If you want to change the default layout;
You should pass layout related components to the **<ThemedLayoutV2 />** component's props.
\`\`\`
// title: App.tsx
import { ThemedLayoutV2 } from "components/layout";
import { ThemedHeaderV2 } from "components/layout/header";
import { ThemedSiderV2 } from "components/layout/sider";
import { ThemedTitleV2 } from "components/layout/title";
const App = () => {
return (
<Refine
/* ... */
>
<ThemedLayoutV2 Header={ThemedHeaderV2} Sider={ThemedSiderV2} Title={ThemedTitleV2}>
/* ... */
</ThemedLayoutV2>
</Refine>
);
}
\`\`\`
`,
files: [
{
src: "./src/components/themedLayoutV2/sider/index.tsx",
dest: "./components/layout/sider.tsx",
transform: (content) => {
let newContent = content;
const imports = getImports(content);
imports.map((importItem) => {
// handle @components import replacement
if (
importItem.importPath === "@components" ||
importItem.importPath === "@hooks"
) {
const newStatement = `import ${importItem.namedImports} from "@refinedev/antd";`;
newContent = newContent.replace(
importItem.statement,
newStatement,
);
}
// add content of ./styles.ts and remove import
if (importItem.importPath === "./styles") {
newContent = newContent.replace(
importItem.statement,
"",
);
let appending = "";
try {
const stylesContent = getFileContent(
join(
dirname(
"./src/components/themedLayoutV2/sider/index.tsx",
),
"/styles.ts",
),
"utf-8",
).replace("export const", "const");
appending = stylesContent;
} catch (err) {
// console.log(err);
}
newContent = appendAfterImports(
newContent,
appending,
);
}
});
return newContent;
},
},
{
src: "./src/components/themedLayoutV2/header/index.tsx",
dest: "./components/layout/header.tsx",
},
{
src: "./src/components/themedLayoutV2/title/index.tsx",
dest: "./components/layout/title.tsx",
},
{
src: "./src/components/themedLayoutV2/index.tsx",
dest: "./components/layout/index.tsx",
transform: (content) => {
let newContent = content;
const imports = getImports(content);
imports.map((importItem) => {
// handle @components import replacement
if (
importItem.importPath === "@components" ||
importItem.importPath === "@contexts" ||
importItem.importPath === "@hooks"
) {
const newStatement = `import ${importItem.namedImports} from "@refinedev/antd";`;
newContent = newContent.replace(
importItem.statement,
newStatement,
);
}
});
return newContent;
},
},
],
},
],
transform: (content) => {
let newContent = content;
const imports = getImports(content);
imports.map((importItem) => {
if (importItem.importPath === "@components") {
const newStatement = `import ${importItem.namedImports} from "@refinedev/antd";`;
newContent = newContent.replace(
importItem.statement,
newStatement,
);
}
// for ui-types
if (importItem.importPath === "@refinedev/ui-types") {
newContent = newContent.replace(importItem.statement, "");
// prop is data-testid
// remove data-testid={*} from props
const testIdPropRegex = /data-testid={.*?}/g;
newContent = newContent.replace(testIdPropRegex, "");
}
// for prop types
if (
importItem.importPath === "../types" ||
importItem.importPath === "./types"
) {
const newStatement = `import type ${importItem.namedImports} from "@refinedev/antd";`;
newContent = newContent.replace(
importItem.statement,
newStatement,
);
}
});
return newContent;
},
},
};

View File

@@ -1,254 +0,0 @@
/* stylelint-disable */
html,
body {
width: 100%;
height: 100%;
}
input::-ms-clear,
input::-ms-reveal {
display: none;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
html {
font-family: sans-serif;
line-height: 1.15;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
-ms-overflow-style: scrollbar;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
@-ms-viewport {
width: device-width;
}
body {
margin: 0;
}
[tabindex="-1"]:focus {
outline: none;
}
hr {
box-sizing: content-box;
height: 0;
overflow: visible;
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin-top: 0;
margin-bottom: 0.5em;
font-weight: 500;
}
p {
margin-top: 0;
margin-bottom: 1em;
}
abbr[title],
abbr[data-original-title] {
-webkit-text-decoration: underline dotted;
text-decoration: underline;
text-decoration: underline dotted;
border-bottom: 0;
cursor: help;
}
address {
margin-bottom: 1em;
font-style: normal;
line-height: inherit;
}
input[type="text"],
input[type="password"],
input[type="number"],
textarea {
-webkit-appearance: none;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1em;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 500;
}
dd {
margin-bottom: 0.5em;
margin-left: 0;
}
blockquote {
margin: 0 0 1em;
}
dfn {
font-style: italic;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 80%;
}
sub,
sup {
position: relative;
font-size: 75%;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
pre,
code,
kbd,
samp {
font-size: 1em;
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier,
monospace;
}
pre {
margin-top: 0;
margin-bottom: 1em;
overflow: auto;
}
figure {
margin: 0 0 1em;
}
img {
vertical-align: middle;
border-style: none;
}
a,
area,
button,
[role="button"],
input:not([type="range"]),
label,
select,
summary,
textarea {
touch-action: manipulation;
}
table {
border-collapse: collapse;
}
caption {
padding-top: 0.75em;
padding-bottom: 0.3em;
text-align: left;
caption-side: bottom;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
color: inherit;
font-size: inherit;
font-family: inherit;
line-height: inherit;
}
button,
input {
overflow: visible;
}
button,
select {
text-transform: none;
}
button,
html [type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
padding: 0;
border-style: none;
}
input[type="radio"],
input[type="checkbox"] {
box-sizing: border-box;
padding: 0;
}
input[type="date"],
input[type="time"],
input[type="datetime-local"],
input[type="month"] {
-webkit-appearance: listbox;
}
textarea {
overflow: auto;
resize: vertical;
}
fieldset {
min-width: 0;
margin: 0;
padding: 0;
border: 0;
}
legend {
display: block;
width: 100%;
max-width: 100%;
margin-bottom: 0.5em;
padding: 0;
color: inherit;
font-size: 1.5em;
line-height: inherit;
white-space: normal;
}
progress {
vertical-align: baseline;
}
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
[type="search"] {
outline-offset: -2px;
-webkit-appearance: none;
}
[type="search"]::-webkit-search-cancel-button,
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
summary {
display: list-item;
}
template {
display: none;
}
[hidden] {
display: none !important;
}
mark {
padding: 0.2em;
background-color: #feffe6;
}

View File

@@ -1,7 +0,0 @@
import { autoSaveIndicatorTests } from "@refinedev/ui-tests";
import { AutoSaveIndicator } from "./";
describe("AutoSaveIndicator", () => {
autoSaveIndicatorTests.bind(this)(AutoSaveIndicator);
});

View File

@@ -1,86 +0,0 @@
import React from "react";
import {
AutoSaveIndicatorProps,
useTranslate,
AutoSaveIndicator as AutoSaveIndicatorCore,
} from "@refinedev/core";
import { Typography, theme } from "antd";
import {
EllipsisOutlined,
SyncOutlined,
CheckCircleOutlined,
ExclamationCircleOutlined,
} from "@ant-design/icons";
export const AutoSaveIndicator: React.FC<AutoSaveIndicatorProps> = ({
status,
elements: {
success = (
<Message
key="autoSave.success"
defaultMessage="saved"
icon={<CheckCircleOutlined />}
/>
),
error = (
<Message
key="autoSave.error"
defaultMessage="auto save failure"
icon={<ExclamationCircleOutlined />}
/>
),
loading = (
<Message
key="autoSave.loading"
defaultMessage="saving..."
icon={<SyncOutlined />}
/>
),
idle = (
<Message
key="autoSave.idle"
defaultMessage="waiting for changes"
icon={<EllipsisOutlined />}
/>
),
} = {},
}) => {
return (
<AutoSaveIndicatorCore
status={status}
elements={{
success,
error,
loading,
idle,
}}
/>
);
};
const Message = ({
key,
defaultMessage,
icon,
}: {
key: string;
defaultMessage: string;
icon: React.ReactNode;
}) => {
const translate = useTranslate();
const { useToken } = theme;
const { token } = useToken();
return (
<Typography.Text
style={{
marginRight: 5,
color: token.colorTextTertiary,
fontSize: ".8rem",
}}
>
{translate(key, defaultMessage)}
<span style={{ marginLeft: ".2rem" }}>{icon}</span>
</Typography.Text>
);
};

View File

@@ -1,53 +0,0 @@
import React, { ReactNode } from "react";
import { Route, Routes } from "react-router-dom";
import { breadcrumbTests } from "@refinedev/ui-tests";
import { render, TestWrapper, ITestWrapperProps, act } from "@test";
import { Breadcrumb } from "./";
const renderBreadcrumb = (
children: ReactNode,
wrapperProps: ITestWrapperProps = {},
) => {
return render(
<Routes>
<Route path="/:resource/:action" element={children} />
</Routes>,
{
wrapper: TestWrapper(wrapperProps),
},
);
};
const DummyDashboard = () => <div>Dashboard</div>;
describe("Breadcrumb", () => {
beforeAll(() => {
jest.spyOn(console, "warn").mockImplementation(jest.fn());
});
breadcrumbTests.bind(this)(Breadcrumb);
it("should render home icon", async () => {
const { container } = renderBreadcrumb(<Breadcrumb />, {
resources: [{ name: "posts" }],
routerInitialEntries: ["/posts/create"],
DashboardPage: DummyDashboard,
});
expect(container.querySelector("svg")).toBeTruthy();
});
it("should not render home icon with 'showhHome' props", async () => {
const { container } = renderBreadcrumb(
<Breadcrumb showHome={false} />,
{
resources: [{ name: "posts" }],
routerInitialEntries: ["/posts/create"],
DashboardPage: DummyDashboard,
},
);
expect(container.querySelector("svg")).toBeFalsy();
});
});

View File

@@ -1,87 +0,0 @@
import React from "react";
import {
useBreadcrumb,
useLink,
useRefineContext,
useRouterContext,
useRouterType,
useResource,
matchResourceFromRoute,
} from "@refinedev/core";
import { RefineBreadcrumbProps } from "@refinedev/ui-types";
import {
Breadcrumb as AntdBreadcrumb,
BreadcrumbProps as AntdBreadcrumbProps,
} from "antd";
import { HomeOutlined } from "@ant-design/icons";
export type BreadcrumbProps = RefineBreadcrumbProps<AntdBreadcrumbProps>;
export const Breadcrumb: React.FC<BreadcrumbProps> = ({
breadcrumbProps,
showHome = true,
hideIcons = false,
meta,
}) => {
const routerType = useRouterType();
const { breadcrumbs } = useBreadcrumb({
meta,
});
const Link = useLink();
const { Link: LegacyLink } = useRouterContext();
const { hasDashboard } = useRefineContext();
const { resources } = useResource();
const rootRouteResource = matchResourceFromRoute("/", resources);
const ActiveLink = routerType === "legacy" ? LegacyLink : Link;
if (breadcrumbs.length === 1) {
return null;
}
const breadCrumbItems = breadcrumbs.map(({ label, icon, href }) => ({
key: `breadcrumb-item-${label}`,
title: (
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "center",
gap: 4,
}}
>
{!hideIcons && icon}
{href ? (
<ActiveLink to={href}>{label}</ActiveLink>
) : (
<span>{label}</span>
)}
</div>
),
}));
const getBreadcrumbItems = () => {
if (showHome && (hasDashboard || rootRouteResource.found)) {
return [
{
key: "breadcrumb-item-home",
title: (
<ActiveLink to="/">
{rootRouteResource?.resource?.meta?.icon ?? (
<HomeOutlined />
)}
</ActiveLink>
),
},
...breadCrumbItems,
];
}
return breadCrumbItems;
};
return <AntdBreadcrumb items={getBreadcrumbItems()} {...breadcrumbProps} />;
};

View File

@@ -1,7 +0,0 @@
import { buttonCloneTests } from "@refinedev/ui-tests";
import { CloneButton } from "./";
describe("Clone Button", () => {
buttonCloneTests.bind(this)(CloneButton);
});

View File

@@ -1,117 +0,0 @@
import React, { useContext } from "react";
import { Button } from "antd";
import { PlusSquareOutlined } from "@ant-design/icons";
import {
useCan,
useNavigation,
useTranslate,
useResource,
useRouterContext,
useRouterType,
useLink,
AccessControlContext,
} from "@refinedev/core";
import {
RefineButtonTestIds,
RefineButtonClassNames,
} from "@refinedev/ui-types";
import { CloneButtonProps } from "../types";
/**
* `<CloneButton>` uses Ant Design's {@link https://ant.design/components/button/ `<Button> component`}.
* It uses the {@link https://refine.dev/docs/api-reference/core/hooks/navigation/useNavigation#clone `clone`} method from {@link https://refine.dev/docs/api-reference/core/hooks/navigation/useNavigation useNavigation} under the hood.
* It can be useful when redirecting the app to the create page with the record id route of resource.
*
* @see {@link https://refine.dev/docs/api-reference/antd/components/buttons/clone-button} for more details.
*/
export const CloneButton: React.FC<CloneButtonProps> = ({
resourceNameOrRouteName: propResourceNameOrRouteName,
resource: resourceNameFromProps,
recordItemId,
hideText = false,
accessControl,
meta,
children,
onClick,
...rest
}) => {
const accessControlContext = useContext(AccessControlContext);
const accessControlEnabled =
accessControl?.enabled ??
accessControlContext.options.buttons.enableAccessControl;
const hideIfUnauthorized =
accessControl?.hideIfUnauthorized ??
accessControlContext.options.buttons.hideIfUnauthorized;
const { cloneUrl: generateCloneUrl } = useNavigation();
const routerType = useRouterType();
const Link = useLink();
const { Link: LegacyLink } = useRouterContext();
const ActiveLink = routerType === "legacy" ? LegacyLink : Link;
const translate = useTranslate();
const { id, resource } = useResource(
resourceNameFromProps ?? propResourceNameOrRouteName,
);
const { data } = useCan({
resource: resource?.name,
action: "create",
params: { id: recordItemId ?? id, resource },
queryOptions: {
enabled: accessControlEnabled,
},
});
const createButtonDisabledTitle = () => {
if (data?.can) return "";
else if (data?.reason) return data.reason;
else
return translate(
"buttons.notAccessTitle",
"You don't have permission to access",
);
};
const cloneUrl =
resource && (recordItemId || id)
? generateCloneUrl(resource, recordItemId! ?? id!, meta)
: "";
if (accessControlEnabled && hideIfUnauthorized && !data?.can) {
return null;
}
return (
<ActiveLink
to={cloneUrl}
replace={false}
onClick={(e: React.PointerEvent<HTMLButtonElement>) => {
if (data?.can === false) {
e.preventDefault();
return;
}
if (onClick) {
e.preventDefault();
onClick(e);
}
}}
>
<Button
icon={<PlusSquareOutlined />}
disabled={data?.can === false}
title={createButtonDisabledTitle()}
data-testid={RefineButtonTestIds.CloneButton}
className={RefineButtonClassNames.CloneButton}
{...rest}
>
{!hideText && (children ?? translate("buttons.clone", "Clone"))}
</Button>
</ActiveLink>
);
};

View File

@@ -1,7 +0,0 @@
import { buttonCreateTests } from "@refinedev/ui-tests";
import { CreateButton } from "./";
describe("Create Button", () => {
buttonCreateTests.bind(this)(CreateButton);
});

View File

@@ -1,117 +0,0 @@
import React, { useContext } from "react";
import { Button } from "antd";
import { PlusSquareOutlined } from "@ant-design/icons";
import {
useNavigation,
useTranslate,
useCan,
useResource,
useRouterContext,
useRouterType,
useLink,
AccessControlContext,
} from "@refinedev/core";
import {
RefineButtonClassNames,
RefineButtonTestIds,
} from "@refinedev/ui-types";
import { CreateButtonProps } from "../types";
/**
* <CreateButton> uses Ant Design's {@link https://ant.design/components/button/ `<Button> component`}.
* It uses the {@link https://refine.dev/docs/api-reference/core/hooks/navigation/useNavigation#create `create`} method from {@link https://refine.dev/docs/api-reference/core/hooks/navigation/useNavigation `useNavigation`} under the hood.
* It can be useful to redirect the app to the create page route of resource}.
*
* @see {@link https://refine.dev/docs/api-reference/antd/components/buttons/create-button} for more details.
*/
export const CreateButton: React.FC<CreateButtonProps> = ({
resource: resourceNameFromProps,
resourceNameOrRouteName: propResourceNameOrRouteName,
hideText = false,
accessControl,
meta,
children,
onClick,
...rest
}) => {
const accessControlContext = useContext(AccessControlContext);
const accessControlEnabled =
accessControl?.enabled ??
accessControlContext.options.buttons.enableAccessControl;
const hideIfUnauthorized =
accessControl?.hideIfUnauthorized ??
accessControlContext.options.buttons.hideIfUnauthorized;
const translate = useTranslate();
const routerType = useRouterType();
const Link = useLink();
const { Link: LegacyLink } = useRouterContext();
const ActiveLink = routerType === "legacy" ? LegacyLink : Link;
const { createUrl: generateCreateUrl } = useNavigation();
const { resource } = useResource(
resourceNameFromProps ?? propResourceNameOrRouteName,
);
const { data } = useCan({
resource: resource?.name,
action: "create",
queryOptions: {
enabled: accessControlEnabled,
},
params: {
resource,
},
});
const createButtonDisabledTitle = () => {
if (data?.can) return "";
else if (data?.reason) return data.reason;
else
return translate(
"buttons.notAccessTitle",
"You don't have permission to access",
);
};
const createUrl = resource ? generateCreateUrl(resource, meta) : "";
if (accessControlEnabled && hideIfUnauthorized && !data?.can) {
return null;
}
return (
<ActiveLink
to={createUrl}
replace={false}
onClick={(e: React.PointerEvent<HTMLButtonElement>) => {
if (data?.can === false) {
e.preventDefault();
return;
}
if (onClick) {
e.preventDefault();
onClick(e);
}
}}
>
<Button
icon={<PlusSquareOutlined />}
disabled={data?.can === false}
title={createButtonDisabledTitle()}
data-testid={RefineButtonTestIds.CreateButton}
className={RefineButtonClassNames.CreateButton}
type="primary"
{...rest}
>
{!hideText &&
(children ?? translate("buttons.create", "Create"))}
</Button>
</ActiveLink>
);
};

View File

@@ -1,6 +0,0 @@
import { buttonDeleteTests } from "@refinedev/ui-tests";
import { DeleteButton } from "./";
describe("Delete Button", () => {
buttonDeleteTests.bind(this)(DeleteButton);
});

Some files were not shown because too many files have changed in this diff Show More