tinacms 1.4.6 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.es.js CHANGED
@@ -10,7 +10,7 @@ import React, { useState, useCallback, useEffect, Fragment, useMemo } from "reac
10
10
  import * as yup from "yup";
11
11
  import { setEditing, useEditState } from "@tinacms/sharedctx";
12
12
  import { diff } from "@graphql-inspector/core";
13
- import { NavLink, useSearchParams, useNavigate, useParams, useLocation, Link, HashRouter, Routes, Route } from "react-router-dom";
13
+ import { NavLink, useSearchParams, useNavigate, useLocation, useParams, Link, HashRouter, Routes, Route } from "react-router-dom";
14
14
  import { Transition, Menu } from "@headlessui/react";
15
15
  import { useWindowWidth } from "@react-hook/window-size";
16
16
  function popupWindow(url, title, window2, w, h) {
@@ -218,12 +218,16 @@ mutation addPendingDocumentMutation(
218
218
  this.contentApiUrl = this.options.customContentApiUrl || `${this.contentApiBase}/${this.tinaGraphQLVersion}/content/${this.options.clientId}/github/${encodedBranch}`;
219
219
  }
220
220
  async request(query, { variables }) {
221
+ const token = await this.getToken();
222
+ const headers = {
223
+ "Content-Type": "application/json"
224
+ };
225
+ if (token == null ? void 0 : token.id_token) {
226
+ headers["Authorization"] = "Bearer " + (token == null ? void 0 : token.id_token);
227
+ }
221
228
  const res = await fetch(this.contentApiUrl, {
222
229
  method: "POST",
223
- headers: {
224
- "Content-Type": "application/json",
225
- Authorization: "Bearer " + (await this.getToken()).id_token
226
- },
230
+ headers,
227
231
  body: JSON.stringify({
228
232
  query: typeof query === "function" ? print(query(gql$1)) : query,
229
233
  variables
@@ -335,12 +339,13 @@ mutation addPendingDocumentMutation(
335
339
  }
336
340
  async fetchWithToken(input, init) {
337
341
  const headers = (init == null ? void 0 : init.headers) || {};
342
+ const token = await this.getToken();
343
+ if (token == null ? void 0 : token.id_token) {
344
+ headers["Authorization"] = "Bearer " + (token == null ? void 0 : token.id_token);
345
+ }
338
346
  return await fetch(input, {
339
347
  ...init,
340
- headers: new Headers({
341
- Authorization: "Bearer " + (await this.getToken()).id_token,
342
- ...headers
343
- })
348
+ headers: new Headers(headers)
344
349
  });
345
350
  }
346
351
  async getUser() {
@@ -617,7 +622,7 @@ class TinaAdminApi {
617
622
  }
618
623
  }`, { variables: { collection, relativePath } });
619
624
  }
620
- async fetchCollection(collectionName, includeDocuments, after, sortKey, order, filterArgs) {
625
+ async fetchCollection(collectionName, includeDocuments, folder = "", after, sortKey, order, filterArgs) {
621
626
  let filter = null;
622
627
  const filterField = filterArgs == null ? void 0 : filterArgs.filterField;
623
628
  if (filterField) {
@@ -654,13 +659,13 @@ class TinaAdminApi {
654
659
  if (includeDocuments === true) {
655
660
  const sort = sortKey || this.schema.getIsTitleFieldName(collectionName);
656
661
  const response = order === "asc" ? await this.api.request(`#graphql
657
- query($collection: String!, $includeDocuments: Boolean!, $sort: String, $limit: Float, $after: String, $filter: DocumentFilter){
662
+ query($collection: String!, $includeDocuments: Boolean!, $sort: String, $limit: Float, $after: String, $filter: DocumentFilter, $folder: String){
658
663
  collection(collection: $collection){
659
664
  name
660
665
  label
661
666
  format
662
667
  templates
663
- documents(sort: $sort, after: $after, first: $limit, filter: $filter) @include(if: $includeDocuments) {
668
+ documents(sort: $sort, after: $after, first: $limit, filter: $filter, folder: $folder) @include(if: $includeDocuments) {
664
669
  totalCount
665
670
  pageInfo {
666
671
  hasPreviousPage
@@ -670,6 +675,11 @@ class TinaAdminApi {
670
675
  }
671
676
  edges {
672
677
  node {
678
+ __typename
679
+ ... on Folder {
680
+ name
681
+ path
682
+ }
673
683
  ... on Document {
674
684
  _sys {
675
685
  title
@@ -690,19 +700,20 @@ class TinaAdminApi {
690
700
  variables: {
691
701
  collection: collectionName,
692
702
  includeDocuments,
703
+ folder,
693
704
  sort,
694
705
  limit: 50,
695
706
  after,
696
707
  filter
697
708
  }
698
709
  }) : await this.api.request(`#graphql
699
- query($collection: String!, $includeDocuments: Boolean!, $sort: String, $limit: Float, $after: String, $filter: DocumentFilter){
710
+ query($collection: String!, $includeDocuments: Boolean!, $sort: String, $limit: Float, $after: String, $filter: DocumentFilter, $folder: String) {
700
711
  collection(collection: $collection){
701
712
  name
702
713
  label
703
714
  format
704
715
  templates
705
- documents(sort: $sort, before: $after, last: $limit, filter: $filter) @include(if: $includeDocuments) {
716
+ documents(sort: $sort, before: $after, last: $limit, filter: $filter, folder: $folder) @include(if: $includeDocuments) {
706
717
  totalCount
707
718
  pageInfo {
708
719
  hasPreviousPage
@@ -712,6 +723,11 @@ class TinaAdminApi {
712
723
  }
713
724
  edges {
714
725
  node {
726
+ __typename
727
+ ... on Folder {
728
+ name
729
+ path
730
+ }
715
731
  ... on Document {
716
732
  _sys {
717
733
  title
@@ -732,6 +748,7 @@ class TinaAdminApi {
732
748
  variables: {
733
749
  collection: collectionName,
734
750
  includeDocuments,
751
+ folder,
735
752
  sort,
736
753
  limit: 50,
737
754
  after,
@@ -1464,6 +1481,9 @@ var styles = `.tina-tailwind {
1464
1481
  .tina-tailwind .flex-shrink-0 {
1465
1482
  flex-shrink: 0;
1466
1483
  }
1484
+ .tina-tailwind .shrink-0 {
1485
+ flex-shrink: 0;
1486
+ }
1467
1487
  .tina-tailwind .flex-grow-0 {
1468
1488
  flex-grow: 0;
1469
1489
  }
@@ -1526,6 +1546,9 @@ var styles = `.tina-tailwind {
1526
1546
  .tina-tailwind .items-stretch {
1527
1547
  align-items: stretch;
1528
1548
  }
1549
+ .tina-tailwind .justify-start {
1550
+ justify-content: flex-start;
1551
+ }
1529
1552
  .tina-tailwind .justify-end {
1530
1553
  justify-content: flex-end;
1531
1554
  }
@@ -1541,6 +1564,9 @@ var styles = `.tina-tailwind {
1541
1564
  .tina-tailwind .gap-0\\.5 {
1542
1565
  gap: 2px;
1543
1566
  }
1567
+ .tina-tailwind .gap-1 {
1568
+ gap: 4px;
1569
+ }
1544
1570
  .tina-tailwind .gap-2 {
1545
1571
  gap: 8px;
1546
1572
  }
@@ -1601,9 +1627,15 @@ var styles = `.tina-tailwind {
1601
1627
  .tina-tailwind .border {
1602
1628
  border-width: 1px;
1603
1629
  }
1630
+ .tina-tailwind .border-0 {
1631
+ border-width: 0;
1632
+ }
1604
1633
  .tina-tailwind .border-b {
1605
1634
  border-bottom-width: 1px;
1606
1635
  }
1636
+ .tina-tailwind .border-r {
1637
+ border-right-width: 1px;
1638
+ }
1607
1639
  .tina-tailwind .border-gray-100 {
1608
1640
  --tw-border-opacity: 1;
1609
1641
  border-color: rgb(237 236 243 / var(--tw-border-opacity));
@@ -1628,6 +1660,12 @@ var styles = `.tina-tailwind {
1628
1660
  --tw-bg-opacity: 1;
1629
1661
  background-color: rgb(246 246 249 / var(--tw-bg-opacity));
1630
1662
  }
1663
+ .tina-tailwind .bg-gray-50\\/30 {
1664
+ background-color: rgb(246 246 249 / .3);
1665
+ }
1666
+ .tina-tailwind .bg-transparent {
1667
+ background-color: transparent;
1668
+ }
1631
1669
  .tina-tailwind .bg-white {
1632
1670
  --tw-bg-opacity: 1;
1633
1671
  background-color: rgb(255 255 255 / var(--tw-bg-opacity));
@@ -1669,6 +1707,9 @@ var styles = `.tina-tailwind {
1669
1707
  .tina-tailwind .fill-current {
1670
1708
  fill: currentColor;
1671
1709
  }
1710
+ .tina-tailwind .p-0 {
1711
+ padding: 0px;
1712
+ }
1672
1713
  .tina-tailwind .px-12 {
1673
1714
  padding-left: 48px;
1674
1715
  padding-right: 48px;
@@ -1737,6 +1778,12 @@ var styles = `.tina-tailwind {
1737
1778
  .tina-tailwind .pl-8 {
1738
1779
  padding-left: 32px;
1739
1780
  }
1781
+ .tina-tailwind .pr-0 {
1782
+ padding-right: 0px;
1783
+ }
1784
+ .tina-tailwind .pr-0\\.5 {
1785
+ padding-right: 2px;
1786
+ }
1740
1787
  .tina-tailwind .pr-3 {
1741
1788
  padding-right: 12px;
1742
1789
  }
@@ -1807,6 +1854,10 @@ var styles = `.tina-tailwind {
1807
1854
  .tina-tailwind .tracking-wide {
1808
1855
  letter-spacing: 0.025em;
1809
1856
  }
1857
+ .tina-tailwind .text-blue-400 {
1858
+ --tw-text-opacity: 1;
1859
+ color: rgb(34 150 254 / var(--tw-text-opacity));
1860
+ }
1810
1861
  .tina-tailwind .text-blue-500 {
1811
1862
  --tw-text-opacity: 1;
1812
1863
  color: rgb(0 132 255 / var(--tw-text-opacity));
@@ -1818,6 +1869,10 @@ var styles = `.tina-tailwind {
1818
1869
  .tina-tailwind .text-current {
1819
1870
  color: currentColor;
1820
1871
  }
1872
+ .tina-tailwind .text-gray-200 {
1873
+ --tw-text-opacity: 1;
1874
+ color: rgb(225 221 236 / var(--tw-text-opacity));
1875
+ }
1821
1876
  .tina-tailwind .text-gray-300 {
1822
1877
  --tw-text-opacity: 1;
1823
1878
  color: rgb(178 173 190 / var(--tw-text-opacity));
@@ -1857,6 +1912,15 @@ var styles = `.tina-tailwind {
1857
1912
  .tina-tailwind .underline {
1858
1913
  text-decoration-line: underline;
1859
1914
  }
1915
+ .tina-tailwind .decoration-blue-200 {
1916
+ text-decoration-color: #85C5FE;
1917
+ }
1918
+ .tina-tailwind .decoration-1 {
1919
+ text-decoration-thickness: 1px;
1920
+ }
1921
+ .tina-tailwind .underline-offset-2 {
1922
+ text-underline-offset: 2px;
1923
+ }
1860
1924
  .tina-tailwind .opacity-0 {
1861
1925
  opacity: 0;
1862
1926
  }
@@ -1968,14 +2032,24 @@ var styles = `.tina-tailwind {
1968
2032
  --tw-bg-opacity: 1;
1969
2033
  background-color: rgb(5 116 228 / var(--tw-bg-opacity));
1970
2034
  }
2035
+ .tina-tailwind .hover\\:bg-gray-50\\/50:hover {
2036
+ background-color: rgb(246 246 249 / .5);
2037
+ }
1971
2038
  .tina-tailwind .hover\\:text-blue-400:hover {
1972
2039
  --tw-text-opacity: 1;
1973
2040
  color: rgb(34 150 254 / var(--tw-text-opacity));
1974
2041
  }
2042
+ .tina-tailwind .hover\\:text-blue-500:hover {
2043
+ --tw-text-opacity: 1;
2044
+ color: rgb(0 132 255 / var(--tw-text-opacity));
2045
+ }
1975
2046
  .tina-tailwind .hover\\:text-blue-600:hover {
1976
2047
  --tw-text-opacity: 1;
1977
2048
  color: rgb(5 116 228 / var(--tw-text-opacity));
1978
2049
  }
2050
+ .tina-tailwind .hover\\:decoration-blue-400:hover {
2051
+ text-decoration-color: #2296fe;
2052
+ }
1979
2053
  .tina-tailwind .hover\\:opacity-100:hover {
1980
2054
  opacity: 1;
1981
2055
  }
@@ -2559,12 +2633,24 @@ const useGetCollections = (cms) => {
2559
2633
  function IoMdClose(props) {
2560
2634
  return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 512 512" }, "child": [{ "tag": "path", "attr": { "d": "M405 136.798L375.202 107 256 226.202 136.798 107 107 136.798 226.202 256 107 375.202 136.798 405 256 285.798 375.202 405 405 375.202 285.798 256z" } }] })(props);
2561
2635
  }
2636
+ function BiArrowBack(props) {
2637
+ return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "d": "M21 11H6.414l5.293-5.293-1.414-1.414L2.586 12l7.707 7.707 1.414-1.414L6.414 13H21z" } }] })(props);
2638
+ }
2639
+ function BiCopy(props) {
2640
+ return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "d": "M20 2H10c-1.103 0-2 .897-2 2v4H4c-1.103 0-2 .897-2 2v10c0 1.103.897 2 2 2h10c1.103 0 2-.897 2-2v-4h4c1.103 0 2-.897 2-2V4c0-1.103-.897-2-2-2zM4 20V10h10l.002 10H4zm16-6h-4v-4c0-1.103-.897-2-2-2h-4V4h10v10z" } }] })(props);
2641
+ }
2562
2642
  function BiEdit(props) {
2563
2643
  return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "d": "m7 17.013 4.413-.015 9.632-9.54c.378-.378.586-.88.586-1.414s-.208-1.036-.586-1.414l-1.586-1.586c-.756-.756-2.075-.752-2.825-.003L7 12.583v4.43zM18.045 4.458l1.589 1.583-1.597 1.582-1.586-1.585 1.594-1.58zM9 13.417l6.03-5.973 1.586 1.586-6.029 5.971L9 15.006v-1.589z" } }, { "tag": "path", "attr": { "d": "M5 21h14c1.103 0 2-.897 2-2v-8.668l-2 2V19H8.158c-.026 0-.053.01-.079.01-.033 0-.066-.009-.1-.01H5V5h6.847l2-2H5c-1.103 0-2 .897-2 2v14c0 1.103.897 2 2 2z" } }] })(props);
2564
2644
  }
2565
2645
  function BiError(props) {
2566
2646
  return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "d": "M11.001 10h2v5h-2zM11 16h2v2h-2z" } }, { "tag": "path", "attr": { "d": "M13.768 4.2C13.42 3.545 12.742 3.138 12 3.138s-1.42.407-1.768 1.063L2.894 18.064a1.986 1.986 0 0 0 .054 1.968A1.984 1.984 0 0 0 4.661 21h14.678c.708 0 1.349-.362 1.714-.968a1.989 1.989 0 0 0 .054-1.968L13.768 4.2zM4.661 19 12 5.137 19.344 19H4.661z" } }] })(props);
2567
2647
  }
2648
+ function BiFile(props) {
2649
+ return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "d": "M19.903 8.586a.997.997 0 0 0-.196-.293l-6-6a.997.997 0 0 0-.293-.196c-.03-.014-.062-.022-.094-.033a.991.991 0 0 0-.259-.051C13.04 2.011 13.021 2 13 2H6c-1.103 0-2 .897-2 2v16c0 1.103.897 2 2 2h12c1.103 0 2-.897 2-2V9c0-.021-.011-.04-.013-.062a.952.952 0 0 0-.051-.259c-.01-.032-.019-.063-.033-.093zM16.586 8H14V5.414L16.586 8zM6 20V4h6v5a1 1 0 0 0 1 1h5l.002 10H6z" } }, { "tag": "path", "attr": { "d": "M8 12h8v2H8zm0 4h8v2H8zm0-8h2v2H8z" } }] })(props);
2650
+ }
2651
+ function BiFolder(props) {
2652
+ return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "d": "M20 5h-8.586L9.707 3.293A.997.997 0 0 0 9 3H4c-1.103 0-2 .897-2 2v14c0 1.103.897 2 2 2h16c1.103 0 2-.897 2-2V7c0-1.103-.897-2-2-2zM4 19V7h16l.002 12H4z" } }] })(props);
2653
+ }
2568
2654
  function BiLogIn(props) {
2569
2655
  return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "d": "m13 16 5-4-5-4v3H4v2h9z" } }, { "tag": "path", "attr": { "d": "M20 3h-9c-1.103 0-2 .897-2 2v4h2V5h9v14h-9v-4H9v4c0 1.103.897 2 2 2h9c1.103 0 2-.897 2-2V5c0-1.103-.897-2-2-2z" } }] })(props);
2570
2656
  }
@@ -2623,7 +2709,7 @@ const Sidebar = ({ cms }) => {
2623
2709
  }),
2624
2710
  RenderNavCollection: ({ collection }) => /* @__PURE__ */ React.createElement(SidebarLink, {
2625
2711
  label: collection.label ? collection.label : collection.name,
2626
- to: `/collections/${collection.name}`,
2712
+ to: `/collections/${collection.name}/~`,
2627
2713
  Icon: ImFilesEmpty
2628
2714
  })
2629
2715
  }), !renderDesktopNav && /* @__PURE__ */ React.createElement(Transition, {
@@ -2660,7 +2746,7 @@ const Sidebar = ({ cms }) => {
2660
2746
  }),
2661
2747
  RenderNavCollection: ({ collection }) => /* @__PURE__ */ React.createElement(SidebarLink, {
2662
2748
  label: collection.label ? collection.label : collection.name,
2663
- to: `/collections/${collection.name}`,
2749
+ to: `/collections/${collection.name}/~`,
2664
2750
  Icon: ImFilesEmpty,
2665
2751
  onClick: () => {
2666
2752
  setMenuIsOpen(false);
@@ -2898,6 +2984,9 @@ const DashboardPage = () => {
2898
2984
  }, "Welcome to Tina!")), /* @__PURE__ */ React.createElement(PageBodyNarrow, null, "This is your dashboard for editing or creating content. Select a collection on the left to begin.")));
2899
2985
  });
2900
2986
  };
2987
+ function RiHome2Line(props) {
2988
+ return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "g", "attr": {}, "child": [{ "tag": "path", "attr": { "fill": "none", "d": "M0 0h24v24H0z" } }, { "tag": "path", "attr": { "d": "M19 21H5a1 1 0 0 1-1-1v-9H1l10.327-9.388a1 1 0 0 1 1.346 0L23 11h-3v9a1 1 0 0 1-1 1zM6 19h12V9.157l-6-5.454-6 5.454V19z" } }] }] })(props);
2989
+ }
2901
2990
  const LoadingPage = () => /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", {
2902
2991
  style: {
2903
2992
  position: "absolute",
@@ -3016,7 +3105,7 @@ const FullscreenError = ({
3016
3105
  className: "w-7 h-auto fill-current opacity-70 mr-1"
3017
3106
  }), " Reload"));
3018
3107
  };
3019
- const useGetCollection = (cms, collectionName, includeDocuments = true, after = "", sortKey, filterArgs) => {
3108
+ const useGetCollection = (cms, collectionName, includeDocuments = true, folder, after = "", sortKey, filterArgs) => {
3020
3109
  const api = new TinaAdminApi(cms);
3021
3110
  const schema = cms.api.tina.schema;
3022
3111
  const collectionExtra = schema.getCollection(collectionName);
@@ -3025,13 +3114,14 @@ const useGetCollection = (cms, collectionName, includeDocuments = true, after =
3025
3114
  const [error, setError] = useState(void 0);
3026
3115
  const [resetState, setResetSate] = useState(0);
3027
3116
  useEffect(() => {
3117
+ let cancelled = false;
3028
3118
  const fetchCollection = async () => {
3029
3119
  var _a;
3030
- if (await api.isAuthenticated()) {
3120
+ if (await api.isAuthenticated() && !folder.loading && !cancelled) {
3031
3121
  const { name, order } = JSON.parse(sortKey || "{}");
3032
3122
  const validSortKey = ((_a = collectionExtra.fields) == null ? void 0 : _a.map((x) => x.name).includes(name)) ? name : void 0;
3033
3123
  try {
3034
- const collection2 = await api.fetchCollection(collectionName, includeDocuments, after, validSortKey, order, filterArgs);
3124
+ const collection2 = await api.fetchCollection(collectionName, includeDocuments, (filterArgs == null ? void 0 : filterArgs.filterField) ? "" : folder.fullyQualifiedName, after, validSortKey, order, filterArgs);
3035
3125
  setCollection(collection2);
3036
3126
  } catch (error2) {
3037
3127
  cms.alerts.error(`[${error2.name}] GetCollection failed: ${error2.message}`);
@@ -3042,15 +3132,29 @@ const useGetCollection = (cms, collectionName, includeDocuments = true, after =
3042
3132
  setLoading(false);
3043
3133
  }
3044
3134
  };
3135
+ if (cancelled)
3136
+ return;
3045
3137
  setLoading(true);
3046
3138
  fetchCollection();
3047
- }, [cms, collectionName, resetState, after, sortKey]);
3139
+ return () => {
3140
+ cancelled = true;
3141
+ };
3142
+ }, [
3143
+ cms,
3144
+ collectionName,
3145
+ folder.loading,
3146
+ folder.fullyQualifiedName,
3147
+ resetState,
3148
+ after,
3149
+ sortKey
3150
+ ]);
3048
3151
  const reFetchCollection = () => setResetSate((x) => x + 1);
3049
3152
  return { collection, loading, error, reFetchCollection, collectionExtra };
3050
3153
  };
3051
3154
  const GetCollection = ({
3052
3155
  cms,
3053
3156
  collectionName,
3157
+ folder,
3054
3158
  includeDocuments = true,
3055
3159
  startCursor,
3056
3160
  sortKey,
@@ -3058,7 +3162,7 @@ const GetCollection = ({
3058
3162
  filterArgs
3059
3163
  }) => {
3060
3164
  const navigate = useNavigate();
3061
- const { collection, loading, error, reFetchCollection, collectionExtra } = useGetCollection(cms, collectionName, includeDocuments, startCursor || "", sortKey, filterArgs) || {};
3165
+ const { collection, loading, error, reFetchCollection, collectionExtra } = useGetCollection(cms, collectionName, includeDocuments, folder, startCursor || "", sortKey, filterArgs) || {};
3062
3166
  useEffect(() => {
3063
3167
  var _a, _b, _c, _d, _e, _f, _g, _h;
3064
3168
  if (loading)
@@ -3068,7 +3172,11 @@ const GetCollection = ({
3068
3172
  const allowDelete = (_f = (_e = (_d = collectionDefinition == null ? void 0 : collectionDefinition.ui) == null ? void 0 : _d.allowedActions) == null ? void 0 : _e.delete) != null ? _f : true;
3069
3173
  if (!allowCreate && !allowDelete && ((_h = (_g = collection.documents) == null ? void 0 : _g.edges) == null ? void 0 : _h.length) === 1) {
3070
3174
  const doc = collection.documents.edges[0].node;
3071
- handleNavigate(navigate, cms, collection, collectionDefinition, doc);
3175
+ const pathToDoc = doc._sys.breadcrumbs;
3176
+ if (folder.fullyQualifiedName) {
3177
+ pathToDoc.unshift("~");
3178
+ }
3179
+ navigate(`/${["collections", "edit", collectionName, ...pathToDoc].join("/")}`, { replace: true });
3072
3180
  }
3073
3181
  }, [(collection == null ? void 0 : collection.name) || "", loading]);
3074
3182
  if (error) {
@@ -3079,6 +3187,42 @@ const GetCollection = ({
3079
3187
  }
3080
3188
  return /* @__PURE__ */ React.createElement(React.Fragment, null, children(collection, loading, reFetchCollection, collectionExtra));
3081
3189
  };
3190
+ const folderRegex = /^.*\/~\/*(.*)$/;
3191
+ const parentFolder = (folder) => {
3192
+ return {
3193
+ ...folder,
3194
+ name: folder.name.split("/").slice(0, -1).join("/"),
3195
+ fullyQualifiedName: folder.fullyQualifiedName.split("/").slice(0, -1).join("/"),
3196
+ parentName: folder.parentName.split("/").slice(0, -1).join("/")
3197
+ };
3198
+ };
3199
+ const useCollectionFolder = () => {
3200
+ const [folder, setFolder] = useState({
3201
+ loading: true,
3202
+ name: "",
3203
+ fullyQualifiedName: "",
3204
+ parentName: ""
3205
+ });
3206
+ const loc = useLocation();
3207
+ useEffect(() => {
3208
+ const match = loc.pathname.match(folderRegex);
3209
+ const update = {
3210
+ name: match ? match[1] : "",
3211
+ fullyQualifiedName: match ? match[1] ? `~/${match[1]}` : "~" : "",
3212
+ loading: false,
3213
+ parentName: ""
3214
+ };
3215
+ if (update.fullyQualifiedName) {
3216
+ const pathParts = update.fullyQualifiedName.split("/");
3217
+ update.parentName = `/${pathParts.slice(0, pathParts.length - 1).join("/")}`;
3218
+ }
3219
+ setFolder({
3220
+ ...folder,
3221
+ ...update
3222
+ });
3223
+ }, [loc]);
3224
+ return folder;
3225
+ };
3082
3226
  const LOCAL_STORAGE_KEY = "tinacms.admin.collection.list.page";
3083
3227
  const isSSR = typeof window === "undefined";
3084
3228
  const TemplateMenu = ({ templates }) => {
@@ -3124,7 +3268,8 @@ const handleNavigate = (navigate, cms, collection, collectionDefinition, documen
3124
3268
  tinaPreview ? navigate(`/~/${routeOverride}`) : window.location.href = routeOverride;
3125
3269
  return null;
3126
3270
  } else {
3127
- navigate(document._sys.breadcrumbs.join("/"));
3271
+ const pathToDoc = document._sys.breadcrumbs;
3272
+ navigate(`/${["collections", "edit", collection.name, ...pathToDoc].join("/")}`, { replace: true });
3128
3273
  }
3129
3274
  };
3130
3275
  const CollectionListPage = () => {
@@ -3143,15 +3288,17 @@ const CollectionListPage = () => {
3143
3288
  after: "",
3144
3289
  booleanEquals: null
3145
3290
  });
3291
+ const [activeSearch, setActiveSearch] = React.useState(false);
3146
3292
  const [endCursor, setEndCursor] = useState("");
3147
3293
  const [prevCursors, setPrevCursors] = useState([]);
3148
3294
  const [sortKey, setSortKey] = useState(isSSR ? "" : window.localStorage.getItem(`${LOCAL_STORAGE_KEY}.${collectionName}`) || JSON.stringify({
3149
3295
  order: "asc",
3150
3296
  name: ""
3151
3297
  }));
3152
- const { order = "asc" } = JSON.parse(sortKey || "{}");
3298
+ const { order = "asc", name: sortName } = JSON.parse(sortKey || "{}");
3153
3299
  const [sortOrder, setSortOrder] = useState(order);
3154
3300
  const loc = useLocation();
3301
+ const folder = useCollectionFolder();
3155
3302
  useEffect(() => {
3156
3303
  setSortKey(window.localStorage.getItem(`${LOCAL_STORAGE_KEY}.${collectionName}`) || JSON.stringify({
3157
3304
  order: "asc",
@@ -3181,6 +3328,7 @@ const CollectionListPage = () => {
3181
3328
  includeDocuments: true,
3182
3329
  startCursor: endCursor,
3183
3330
  sortKey,
3331
+ folder,
3184
3332
  filterArgs: collectionName === vars.collection ? vars : {
3185
3333
  collection: collectionName,
3186
3334
  relativePath: "",
@@ -3199,6 +3347,7 @@ const CollectionListPage = () => {
3199
3347
  const admin = cms.api.admin;
3200
3348
  const pageInfo = collection.documents.pageInfo;
3201
3349
  const fields = (_a = collectionExtra.fields) == null ? void 0 : _a.filter((x) => ["string", "number", "datetime", "boolean"].includes(x.type));
3350
+ const sortField = fields.find((field) => field.name === sortName);
3202
3351
  const filterFields = (_b = collectionExtra.fields) == null ? void 0 : _b.filter((x) => {
3203
3352
  return ["string", "datetime", "boolean"].includes(x.type) && !x.list;
3204
3353
  });
@@ -3209,6 +3358,7 @@ const CollectionListPage = () => {
3209
3358
  const collectionDefinition = cms.api.tina.schema.getCollection(collection.name);
3210
3359
  const allowCreate = (_e = (_d = (_c = collectionDefinition == null ? void 0 : collectionDefinition.ui) == null ? void 0 : _c.allowedActions) == null ? void 0 : _d.create) != null ? _e : true;
3211
3360
  const allowDelete = (_h = (_g = (_f = collectionDefinition == null ? void 0 : collectionDefinition.ui) == null ? void 0 : _f.allowedActions) == null ? void 0 : _g.delete) != null ? _h : true;
3361
+ const folderView = folder.fullyQualifiedName !== "";
3212
3362
  return /* @__PURE__ */ React.createElement(React.Fragment, null, deleteModalOpen && /* @__PURE__ */ React.createElement(DeleteModal, {
3213
3363
  filename: vars.relativePath,
3214
3364
  deleteFunc: async () => {
@@ -3256,9 +3406,9 @@ const CollectionListPage = () => {
3256
3406
  className: "flex flex-col gap-4"
3257
3407
  }, /* @__PURE__ */ React.createElement("h3", {
3258
3408
  className: "font-sans text-2xl text-gray-700"
3259
- }, collection.label ? collection.label : collection.name), (fields == null ? void 0 : fields.length) > 0 && /* @__PURE__ */ React.createElement("div", {
3409
+ }, collection.label ? collection.label : collection.name), /* @__PURE__ */ React.createElement("div", {
3260
3410
  className: "flex gap-4 items-end flex-wrap"
3261
- }, /* @__PURE__ */ React.createElement("div", {
3411
+ }, (fields == null ? void 0 : fields.length) > 0 && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", {
3262
3412
  className: "flex flex-col gap-2 items-start"
3263
3413
  }, /* @__PURE__ */ React.createElement("label", {
3264
3414
  htmlFor: "sort",
@@ -3421,6 +3571,7 @@ const CollectionListPage = () => {
3421
3571
  className: "flex gap-3"
3422
3572
  }, /* @__PURE__ */ React.createElement(Button, {
3423
3573
  onClick: () => {
3574
+ setActiveSearch(true);
3424
3575
  setEndCursor("");
3425
3576
  setPrevCursors([]);
3426
3577
  reFetchCollection();
@@ -3431,8 +3582,10 @@ const CollectionListPage = () => {
3431
3582
  className: "w-5 h-full ml-1.5 opacity-70"
3432
3583
  })), (vars.startsWith || vars.after || vars.before || vars.booleanEquals) && /* @__PURE__ */ React.createElement(Button, {
3433
3584
  onClick: () => {
3585
+ setActiveSearch(false);
3434
3586
  setVars((old) => ({
3435
3587
  ...old,
3588
+ filterField: "",
3436
3589
  startsWith: "",
3437
3590
  after: "",
3438
3591
  before: "",
@@ -3445,10 +3598,16 @@ const CollectionListPage = () => {
3445
3598
  variant: "white"
3446
3599
  }, "Clear", " ", /* @__PURE__ */ React.createElement(BiX, {
3447
3600
  className: "w-5 h-full ml-1 opacity-70"
3448
- })))))), /* @__PURE__ */ React.createElement("div", {
3601
+ }))))))), /* @__PURE__ */ React.createElement("div", {
3449
3602
  className: "flex self-end justify-self-end"
3450
3603
  }, !collection.templates && allowCreate && /* @__PURE__ */ React.createElement(Link, {
3451
- to: `new`,
3604
+ to: `/${folder.fullyQualifiedName ? [
3605
+ "collections",
3606
+ "new",
3607
+ collectionName,
3608
+ "~",
3609
+ folder.name
3610
+ ].join("/") : ["collections", "new", collectionName].join("/")}`,
3452
3611
  className: "icon-parent inline-flex items-center font-medium focus:outline-none focus:ring-2 focus:shadow-outline text-center rounded-full justify-center transition-all duration-150 ease-out whitespace-nowrap shadow text-white bg-blue-500 hover:bg-blue-600 focus:ring-blue-500 text-sm h-10 px-6"
3453
3612
  }, "Create New", " ", /* @__PURE__ */ React.createElement(BiPlus, {
3454
3613
  className: "w-5 h-full ml-1 opacity-70"
@@ -3456,25 +3615,73 @@ const CollectionListPage = () => {
3456
3615
  templates: collection.templates
3457
3616
  })))), /* @__PURE__ */ React.createElement(PageBody, null, /* @__PURE__ */ React.createElement("div", {
3458
3617
  className: "w-full mx-auto max-w-screen-xl"
3459
- }, documents.length > 0 ? /* @__PURE__ */ React.createElement("table", {
3618
+ }, sortField && !sortField.required && /* @__PURE__ */ React.createElement("p", {
3619
+ className: "mb-4 text-gray-500"
3620
+ }, /* @__PURE__ */ React.createElement("em", null, "Sorting on a non-required field. Some documents may be excluded (if they don't have a value for", " ", sortName, ")")), documents.length > 0 ? /* @__PURE__ */ React.createElement("table", {
3460
3621
  className: "table-auto shadow bg-white border-b border-gray-200 w-full max-w-full rounded-lg"
3461
3622
  }, /* @__PURE__ */ React.createElement("tbody", {
3462
3623
  className: "divide-y divide-gray-150"
3463
- }, documents.map((document) => {
3624
+ }, !activeSearch && folder.name && /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("td", {
3625
+ colSpan: 5
3626
+ }, /* @__PURE__ */ React.createElement(Breadcrumb, {
3627
+ folder,
3628
+ navigate,
3629
+ collectionName
3630
+ }))), documents.map((document) => {
3464
3631
  var _a2;
3632
+ if (document.node.__typename === "Folder") {
3633
+ return /* @__PURE__ */ React.createElement("tr", {
3634
+ key: `folder-${document.node.path}`
3635
+ }, /* @__PURE__ */ React.createElement("td", {
3636
+ className: "pl-5 pr-3 py-3 truncate max-w-0"
3637
+ }, /* @__PURE__ */ React.createElement("a", {
3638
+ className: "text-blue-600 hover:text-blue-400 flex items-center gap-3 cursor-pointer truncate",
3639
+ onClick: () => {
3640
+ navigate(`/${[
3641
+ "collections",
3642
+ collectionName,
3643
+ document.node.path
3644
+ ].join("/")}`, { replace: true });
3645
+ }
3646
+ }, /* @__PURE__ */ React.createElement(BiFolder, {
3647
+ className: "inline-block h-6 w-auto flex-shrink-0 opacity-70"
3648
+ }), /* @__PURE__ */ React.createElement("span", {
3649
+ className: "truncate block"
3650
+ }, /* @__PURE__ */ React.createElement("span", {
3651
+ className: "block text-xs text-gray-400 mb-1 uppercase"
3652
+ }, "Name"), /* @__PURE__ */ React.createElement("span", {
3653
+ className: "h-5 leading-5 block truncate"
3654
+ }, /* @__PURE__ */ React.createElement("span", null, document.node.name))))), /* @__PURE__ */ React.createElement("td", {
3655
+ className: "px-3 py-3 truncate max-w-0",
3656
+ colSpan: 4
3657
+ }, /* @__PURE__ */ React.createElement("span", {
3658
+ className: "block text-xs text-gray-400 mb-1 uppercase"
3659
+ }, "Path"), /* @__PURE__ */ React.createElement("span", {
3660
+ className: "leading-5 block text-sm font-medium text-gray-900 truncate"
3661
+ }, document.node.path.substring(2).split("/").map((node) => {
3662
+ return /* @__PURE__ */ React.createElement("span", {
3663
+ key: node
3664
+ }, /* @__PURE__ */ React.createElement("span", {
3665
+ className: "text-gray-300 pr-0.5"
3666
+ }, "/"), /* @__PURE__ */ React.createElement("span", {
3667
+ className: "pr-0.5"
3668
+ }, node));
3669
+ }))));
3670
+ }
3465
3671
  const hasTitle = Boolean(document.node._sys.title);
3466
3672
  const subfolders = document.node._sys.breadcrumbs.slice(0, -1).join("/");
3467
3673
  return /* @__PURE__ */ React.createElement("tr", {
3468
3674
  key: `document-${document.node._sys.relativePath}`,
3469
3675
  className: ""
3470
3676
  }, /* @__PURE__ */ React.createElement("td", {
3471
- className: "pl-5 pr-3 py-2 truncate max-w-0"
3677
+ className: "pl-5 pr-3 py-3 truncate max-w-0",
3678
+ colSpan: hasTitle ? 1 : 2
3472
3679
  }, /* @__PURE__ */ React.createElement("a", {
3473
3680
  className: "text-blue-600 hover:text-blue-400 flex items-center gap-3 cursor-pointer truncate",
3474
3681
  onClick: () => {
3475
3682
  handleNavigate(navigate, cms, collection, collectionDefinition, document.node);
3476
3683
  }
3477
- }, /* @__PURE__ */ React.createElement(BiEdit, {
3684
+ }, /* @__PURE__ */ React.createElement(BiFile, {
3478
3685
  className: "inline-block h-6 w-auto flex-shrink-0 opacity-70"
3479
3686
  }), /* @__PURE__ */ React.createElement("span", {
3480
3687
  className: "truncate block"
@@ -3482,24 +3689,24 @@ const CollectionListPage = () => {
3482
3689
  className: "block text-xs text-gray-400 mb-1 uppercase"
3483
3690
  }, hasTitle ? "Title" : "Filename"), /* @__PURE__ */ React.createElement("span", {
3484
3691
  className: "h-5 leading-5 block truncate"
3485
- }, !hasTitle && subfolders && /* @__PURE__ */ React.createElement("span", {
3692
+ }, !folderView && !hasTitle && subfolders && /* @__PURE__ */ React.createElement("span", {
3486
3693
  className: "text-xs text-gray-400"
3487
3694
  }, `${subfolders}/`), /* @__PURE__ */ React.createElement("span", null, hasTitle ? (_a2 = document.node._sys) == null ? void 0 : _a2.title : document.node._sys.filename))))), hasTitle && /* @__PURE__ */ React.createElement("td", {
3488
- className: "px-3 py-4 truncate max-w-0 "
3695
+ className: "px-3 py-3 truncate max-w-0"
3489
3696
  }, /* @__PURE__ */ React.createElement("span", {
3490
3697
  className: "block text-xs text-gray-400 mb-1 uppercase"
3491
3698
  }, "Filename"), /* @__PURE__ */ React.createElement("span", {
3492
3699
  className: "h-5 leading-5 block text-sm font-medium text-gray-900 truncate"
3493
- }, subfolders && /* @__PURE__ */ React.createElement("span", {
3700
+ }, !folderView && subfolders && /* @__PURE__ */ React.createElement("span", {
3494
3701
  className: "text-xs text-gray-400"
3495
3702
  }, `${subfolders}/`), /* @__PURE__ */ React.createElement("span", null, document.node._sys.filename))), /* @__PURE__ */ React.createElement("td", {
3496
- className: "px-3 py-4 truncate w-[15%]"
3703
+ className: "px-3 py-3 truncate w-[15%]"
3497
3704
  }, /* @__PURE__ */ React.createElement("span", {
3498
3705
  className: "block text-xs text-gray-400 mb-1 uppercase"
3499
3706
  }, "Extension"), /* @__PURE__ */ React.createElement("span", {
3500
3707
  className: "h-5 leading-5 block text-sm font-medium text-gray-900"
3501
3708
  }, document.node._sys.extension)), /* @__PURE__ */ React.createElement("td", {
3502
- className: "px-3 py-4 truncate w-[15%]"
3709
+ className: "px-3 py-3 truncate w-[15%]"
3503
3710
  }, /* @__PURE__ */ React.createElement("span", {
3504
3711
  className: "block text-xs text-gray-400 mb-1 uppercase"
3505
3712
  }, "Template"), /* @__PURE__ */ React.createElement("span", {
@@ -3515,7 +3722,35 @@ const CollectionListPage = () => {
3515
3722
  size: "1.3rem"
3516
3723
  }),
3517
3724
  onMouseDown: () => {
3518
- navigate(`${document.node._sys.breadcrumbs.join("/")}`, { replace: true });
3725
+ const pathToDoc = document.node._sys.breadcrumbs;
3726
+ if (folder.fullyQualifiedName) {
3727
+ pathToDoc.unshift("~");
3728
+ }
3729
+ navigate(`/${[
3730
+ "collections",
3731
+ "edit",
3732
+ collectionName,
3733
+ ...pathToDoc
3734
+ ].join("/")}`, { replace: true });
3735
+ }
3736
+ },
3737
+ allowCreate && {
3738
+ name: "duplicate",
3739
+ label: "Duplicate",
3740
+ Icon: /* @__PURE__ */ React.createElement(BiCopy, {
3741
+ size: "1.3rem"
3742
+ }),
3743
+ onMouseDown: () => {
3744
+ const pathToDoc = document.node._sys.breadcrumbs;
3745
+ if (folder.fullyQualifiedName) {
3746
+ pathToDoc.unshift("~");
3747
+ }
3748
+ navigate(`/${[
3749
+ "collections",
3750
+ "duplicate",
3751
+ collectionName,
3752
+ ...pathToDoc
3753
+ ].join("/")}`, { replace: true });
3519
3754
  }
3520
3755
  },
3521
3756
  allowDelete && {
@@ -3577,6 +3812,51 @@ const CollectionListPage = () => {
3577
3812
  }));
3578
3813
  });
3579
3814
  };
3815
+ const Breadcrumb = ({ folder, navigate, collectionName }) => {
3816
+ const folderArray = folder.name.split("/");
3817
+ return /* @__PURE__ */ React.createElement("div", {
3818
+ className: "w-full bg-gray-50/30 flex items-stretch"
3819
+ }, /* @__PURE__ */ React.createElement("button", {
3820
+ onClick: () => {
3821
+ const folders = folder.fullyQualifiedName.split("/");
3822
+ navigate(`/${[
3823
+ "collections",
3824
+ collectionName,
3825
+ ...folders.slice(0, folders.length - 1)
3826
+ ].join("/")}`, { replace: true });
3827
+ },
3828
+ className: "px-3 py-2 bg-white hover:bg-gray-50/50 transition ease-out duration-100 border-r border-gray-100 text-blue-500 hover:text-blue-600"
3829
+ }, /* @__PURE__ */ React.createElement(BiArrowBack, {
3830
+ className: "w-6 h-full opacity-70"
3831
+ })), /* @__PURE__ */ React.createElement("span", {
3832
+ className: "px-3 py-2 text-gray-600 flex flex-wrap items-center justify-start gap-1"
3833
+ }, /* @__PURE__ */ React.createElement("button", {
3834
+ onClick: () => {
3835
+ navigate(`/collections/${collectionName}/~`, {
3836
+ replace: true
3837
+ });
3838
+ },
3839
+ className: "shrink-0 bg-transparent p-0 border-0 text-blue-400 hover:text-blue-500 transition-all ease-out duration-100 opacity-70 hover:opacity-100"
3840
+ }, /* @__PURE__ */ React.createElement(RiHome2Line, {
3841
+ className: "w-5 h-auto"
3842
+ })), folderArray.map((node, index) => {
3843
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("span", {
3844
+ className: "text-gray-200 shrink-0"
3845
+ }, "/"), index < folderArray.length - 1 ? /* @__PURE__ */ React.createElement("button", {
3846
+ className: "bg-transparent whitespace-nowrap truncate p-0 border-0 text-blue-500 hover:text-blue-600 transition-all ease-out duration-100 underline underline-offset-2 decoration-1 decoration-blue-200 hover:decoration-blue-400",
3847
+ onClick: () => {
3848
+ const folders = folder.fullyQualifiedName.split("/");
3849
+ navigate(`/${[
3850
+ "collections",
3851
+ collectionName,
3852
+ ...folders.slice(0, folders.length - (folders.length - (index + 2)))
3853
+ ].join("/")}`, { replace: true });
3854
+ }
3855
+ }, node) : /* @__PURE__ */ React.createElement("span", {
3856
+ className: "whitespace-nowrap truncate"
3857
+ }, node));
3858
+ })));
3859
+ };
3580
3860
  const NoDocumentsPlaceholder = () => {
3581
3861
  return /* @__PURE__ */ React.createElement("div", {
3582
3862
  className: "text-center px-5 py-3 flex flex-col items-center justify-center shadow border border-gray-100 bg-gray-50 border-b border-gray-200 w-full max-w-full rounded-lg"
@@ -3639,10 +3919,10 @@ function FaLock(props) {
3639
3919
  function FaUnlock(props) {
3640
3920
  return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 448 512" }, "child": [{ "tag": "path", "attr": { "d": "M400 256H152V152.9c0-39.6 31.7-72.5 71.3-72.9 40-.4 72.7 32.1 72.7 72v16c0 13.3 10.7 24 24 24h32c13.3 0 24-10.7 24-24v-16C376 68 307.5-.3 223.5 0 139.5.3 72 69.5 72 153.5V256H48c-26.5 0-48 21.5-48 48v160c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V304c0-26.5-21.5-48-48-48z" } }] })(props);
3641
3921
  }
3642
- const createDocument = async (cms, collection, template, mutationInfo, values) => {
3922
+ const createDocument = async (cms, collection, template, mutationInfo, folder, values) => {
3643
3923
  const api = new TinaAdminApi(cms);
3644
3924
  const { filename, ...leftover } = values;
3645
- const relativePath = `${filename}.${collection.format}`;
3925
+ const relativePath = `${folder ? `${folder}/` : ""}${filename}.${collection.format}`;
3646
3926
  const params = api.schema.transformPayload(collection.name, {
3647
3927
  _collection: collection.name,
3648
3928
  ...template && { _template: template.name },
@@ -3658,10 +3938,12 @@ const createDocument = async (cms, collection, template, mutationInfo, values) =
3658
3938
  }
3659
3939
  };
3660
3940
  const CollectionCreatePage = () => {
3941
+ const folder = useCollectionFolder();
3661
3942
  const { collectionName, templateName } = useParams();
3662
3943
  return /* @__PURE__ */ React.createElement(GetCMS, null, (cms) => /* @__PURE__ */ React.createElement(GetCollection, {
3663
3944
  cms,
3664
3945
  collectionName,
3946
+ folder,
3665
3947
  includeDocuments: false
3666
3948
  }, (collection) => {
3667
3949
  const mutationInfo = {
@@ -3672,7 +3954,8 @@ const CollectionCreatePage = () => {
3672
3954
  cms,
3673
3955
  collection,
3674
3956
  templateName,
3675
- mutationInfo
3957
+ mutationInfo,
3958
+ folder
3676
3959
  });
3677
3960
  }));
3678
3961
  };
@@ -3694,7 +3977,14 @@ const FilenameInput = (props) => {
3694
3977
  className: `text-blue-500 absolute top-1/2 left-2 -translate-y-1/2 pointer-events-none h-5 w-auto transition-opacity duration-150 ease-out ${!filenameTouched && !props.readonly ? "opacity-0 group-hover:opacity-80 group-active:opacity-80" : "opacity-0"}`
3695
3978
  }));
3696
3979
  };
3697
- const RenderForm$1 = ({ cms, collection, templateName, mutationInfo }) => {
3980
+ const RenderForm$1 = ({
3981
+ cms,
3982
+ collection,
3983
+ folder,
3984
+ templateName,
3985
+ mutationInfo,
3986
+ customDefaults
3987
+ }) => {
3698
3988
  var _a, _b, _c, _d, _e, _f;
3699
3989
  const navigate = useNavigate();
3700
3990
  const [formIsPristine, setFormIsPristine] = useState(true);
@@ -3720,7 +4010,7 @@ const RenderForm$1 = ({ cms, collection, templateName, mutationInfo }) => {
3720
4010
  };
3721
4011
  }
3722
4012
  }
3723
- const defaultItem = ((_d = template.ui) == null ? void 0 : _d.defaultItem) || (template == null ? void 0 : template.defaultItem);
4013
+ const defaultItem = customDefaults || ((_d = template.ui) == null ? void 0 : _d.defaultItem) || (template == null ? void 0 : template.defaultItem);
3724
4014
  const form = useMemo(() => {
3725
4015
  var _a2, _b2;
3726
4016
  return new Form({
@@ -3777,9 +4067,12 @@ const RenderForm$1 = ({ cms, collection, templateName, mutationInfo }) => {
3777
4067
  ],
3778
4068
  onSubmit: async (values) => {
3779
4069
  try {
3780
- await createDocument(cms, collection, template, mutationInfo, values);
4070
+ const folderName = folder.fullyQualifiedName ? folder.name : "";
4071
+ await createDocument(cms, collection, template, mutationInfo, folderName, values);
3781
4072
  cms.alerts.success("Document created!");
3782
- navigate(`/collections/${collection.name}`);
4073
+ setTimeout(() => {
4074
+ navigate(`/collections/${collection.name}${folder.fullyQualifiedName ? `/${folder.fullyQualifiedName}` : ""}`);
4075
+ }, 10);
3783
4076
  } catch (error) {
3784
4077
  console.error(error);
3785
4078
  const defaultErrorText = "There was a problem saving your document.";
@@ -3806,7 +4099,7 @@ const RenderForm$1 = ({ cms, collection, templateName, mutationInfo }) => {
3806
4099
  }, /* @__PURE__ */ React.createElement("span", {
3807
4100
  className: "block text-sm leading-tight uppercase text-gray-400 mb-1"
3808
4101
  }, /* @__PURE__ */ React.createElement(Link, {
3809
- to: `/collections/${collection.name}`,
4102
+ to: `/collections/${collection.name}${folder.fullyQualifiedName ? `/${folder.fullyQualifiedName}` : ""}`,
3810
4103
  className: "inline-block text-current hover:text-blue-400 focus:underline focus:outline-none focus:text-blue-400 font-medium transition-colors duration-150 ease-out"
3811
4104
  }, collection.label ? collection.label : collection.name), /* @__PURE__ */ React.createElement(HiChevronRight, {
3812
4105
  className: "inline-block -mt-0.5 opacity-50"
@@ -3859,6 +4152,38 @@ const GetDocument = ({
3859
4152
  }
3860
4153
  return /* @__PURE__ */ React.createElement(React.Fragment, null, children(document, loading));
3861
4154
  };
4155
+ const CollectionDuplicatePage = () => {
4156
+ const folder = useCollectionFolder();
4157
+ const { collectionName, ...rest } = useParams();
4158
+ const { "*": filename } = rest;
4159
+ return /* @__PURE__ */ React.createElement(GetCMS, null, (cms) => /* @__PURE__ */ React.createElement(GetCollection, {
4160
+ cms,
4161
+ collectionName,
4162
+ folder,
4163
+ includeDocuments: false
4164
+ }, (collection) => {
4165
+ const relativePath = `${filename.startsWith("~/") ? filename.substring(2) : filename}.${collection.format}`;
4166
+ const mutationInfo = {
4167
+ includeCollection: true,
4168
+ includeTemplate: !!collection.templates
4169
+ };
4170
+ return /* @__PURE__ */ React.createElement(GetDocument, {
4171
+ cms,
4172
+ collectionName: collection.name,
4173
+ relativePath
4174
+ }, (document) => {
4175
+ var _a;
4176
+ return /* @__PURE__ */ React.createElement(RenderForm$1, {
4177
+ cms,
4178
+ collection,
4179
+ templateName: (_a = document._values) == null ? void 0 : _a._template,
4180
+ folder: parentFolder(folder),
4181
+ mutationInfo,
4182
+ customDefaults: document._values
4183
+ });
4184
+ });
4185
+ }));
4186
+ };
3862
4187
  const updateDocument = async (cms, relativePath, collection, mutationInfo, values) => {
3863
4188
  const api = new TinaAdminApi(cms);
3864
4189
  const params = api.schema.transformPayload(collection.name, values);
@@ -3873,13 +4198,16 @@ const updateDocument = async (cms, relativePath, collection, mutationInfo, value
3873
4198
  };
3874
4199
  const CollectionUpdatePage = () => {
3875
4200
  const { collectionName, ...rest } = useParams();
4201
+ const folder = useCollectionFolder();
3876
4202
  const { "*": filename } = rest;
4203
+ const resolvedFile = folder.fullyQualifiedName ? folder.name : filename;
3877
4204
  return /* @__PURE__ */ React.createElement(GetCMS, null, (cms) => /* @__PURE__ */ React.createElement(GetCollection, {
3878
4205
  cms,
3879
4206
  collectionName,
4207
+ folder,
3880
4208
  includeDocuments: false
3881
4209
  }, (collection) => {
3882
- const relativePath = `${filename}.${collection.format}`;
4210
+ const relativePath = `${resolvedFile}.${collection.format}`;
3883
4211
  const mutationInfo = {
3884
4212
  includeCollection: true,
3885
4213
  includeTemplate: !!collection.templates
@@ -3891,7 +4219,7 @@ const CollectionUpdatePage = () => {
3891
4219
  }, (document) => /* @__PURE__ */ React.createElement(RenderForm, {
3892
4220
  cms,
3893
4221
  document,
3894
- filename,
4222
+ filename: resolvedFile,
3895
4223
  relativePath,
3896
4224
  collection,
3897
4225
  mutationInfo
@@ -3909,6 +4237,7 @@ const RenderForm = ({
3909
4237
  var _a, _b;
3910
4238
  const [formIsPristine, setFormIsPristine] = useState(true);
3911
4239
  const schema = cms.api.tina.schema;
4240
+ const parentFolder2 = relativePath.split("/").slice(0, -1).join("/");
3912
4241
  const schemaCollection = schema.getCollection(collection.name);
3913
4242
  const template = schema.getTemplateForData({
3914
4243
  collection: schemaCollection,
@@ -3950,7 +4279,7 @@ const RenderForm = ({
3950
4279
  }, /* @__PURE__ */ React.createElement("span", {
3951
4280
  className: "block text-sm leading-tight uppercase text-gray-400 mb-1"
3952
4281
  }, /* @__PURE__ */ React.createElement(Link, {
3953
- to: `/collections/${collection.name}`,
4282
+ to: `/collections/${collection.name}/~${parentFolder2}`,
3954
4283
  className: "inline-block text-current hover:text-blue-400 focus:underline focus:outline-none focus:text-blue-400 font-medium transition-colors duration-150 ease-out"
3955
4284
  }, collection.label ? collection.label : collection.name), /* @__PURE__ */ React.createElement(HiChevronRight, {
3956
4285
  className: "inline-block -mt-0.5 opacity-50"
@@ -4111,22 +4440,42 @@ const TinaAdmin = ({
4111
4440
  path: "graphql",
4112
4441
  element: /* @__PURE__ */ React.createElement(PlainLayout, null, /* @__PURE__ */ React.createElement(Playground, null))
4113
4442
  }), /* @__PURE__ */ React.createElement(Route, {
4114
- path: "collections/:collectionName/new",
4443
+ path: "collections/new/:collectionName",
4115
4444
  element: /* @__PURE__ */ React.createElement(DefaultWrapper, {
4116
4445
  cms
4117
4446
  }, /* @__PURE__ */ React.createElement(CollectionCreatePage, null))
4118
4447
  }), /* @__PURE__ */ React.createElement(Route, {
4119
- path: "collections/:collectionName/:templateName/new",
4448
+ path: "collections/duplicate/:collectionName/~/*",
4449
+ element: /* @__PURE__ */ React.createElement(DefaultWrapper, {
4450
+ cms
4451
+ }, /* @__PURE__ */ React.createElement(CollectionDuplicatePage, null))
4452
+ }), /* @__PURE__ */ React.createElement(Route, {
4453
+ path: "collections/duplicate/:collectionName/*",
4454
+ element: /* @__PURE__ */ React.createElement(DefaultWrapper, {
4455
+ cms
4456
+ }, /* @__PURE__ */ React.createElement(CollectionDuplicatePage, null))
4457
+ }), /* @__PURE__ */ React.createElement(Route, {
4458
+ path: "collections/new/:collectionName/:templateName",
4120
4459
  element: /* @__PURE__ */ React.createElement(DefaultWrapper, {
4121
4460
  cms
4122
4461
  }, /* @__PURE__ */ React.createElement(CollectionCreatePage, null))
4123
4462
  }), /* @__PURE__ */ React.createElement(Route, {
4124
- path: "collections/:collectionName/*",
4463
+ path: "collections/new/:collectionName/:templateName/~/*",
4464
+ element: /* @__PURE__ */ React.createElement(DefaultWrapper, {
4465
+ cms
4466
+ }, /* @__PURE__ */ React.createElement(CollectionCreatePage, null))
4467
+ }), /* @__PURE__ */ React.createElement(Route, {
4468
+ path: "collections/new/:collectionName/~/*",
4469
+ element: /* @__PURE__ */ React.createElement(DefaultWrapper, {
4470
+ cms
4471
+ }, /* @__PURE__ */ React.createElement(CollectionCreatePage, null))
4472
+ }), /* @__PURE__ */ React.createElement(Route, {
4473
+ path: "collections/edit/:collectionName/*",
4125
4474
  element: /* @__PURE__ */ React.createElement(DefaultWrapper, {
4126
4475
  cms
4127
4476
  }, /* @__PURE__ */ React.createElement(CollectionUpdatePage, null))
4128
4477
  }), /* @__PURE__ */ React.createElement(Route, {
4129
- path: "collections/:collectionName",
4478
+ path: "collections/:collectionName/*",
4130
4479
  element: /* @__PURE__ */ React.createElement(DefaultWrapper, {
4131
4480
  cms
4132
4481
  }, /* @__PURE__ */ React.createElement(CollectionListPage, null))