tinacms 1.4.5 → 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.js CHANGED
@@ -233,12 +233,16 @@ mutation addPendingDocumentMutation(
233
233
  this.contentApiUrl = this.options.customContentApiUrl || `${this.contentApiBase}/${this.tinaGraphQLVersion}/content/${this.options.clientId}/github/${encodedBranch}`;
234
234
  }
235
235
  async request(query, { variables }) {
236
+ const token = await this.getToken();
237
+ const headers = {
238
+ "Content-Type": "application/json"
239
+ };
240
+ if (token == null ? void 0 : token.id_token) {
241
+ headers["Authorization"] = "Bearer " + (token == null ? void 0 : token.id_token);
242
+ }
236
243
  const res = await fetch(this.contentApiUrl, {
237
244
  method: "POST",
238
- headers: {
239
- "Content-Type": "application/json",
240
- Authorization: "Bearer " + (await this.getToken()).id_token
241
- },
245
+ headers,
242
246
  body: JSON.stringify({
243
247
  query: typeof query === "function" ? graphql.print(query(gql__default["default"])) : query,
244
248
  variables
@@ -350,12 +354,13 @@ mutation addPendingDocumentMutation(
350
354
  }
351
355
  async fetchWithToken(input, init) {
352
356
  const headers = (init == null ? void 0 : init.headers) || {};
357
+ const token = await this.getToken();
358
+ if (token == null ? void 0 : token.id_token) {
359
+ headers["Authorization"] = "Bearer " + (token == null ? void 0 : token.id_token);
360
+ }
353
361
  return await fetch(input, {
354
362
  ...init,
355
- headers: new Headers({
356
- Authorization: "Bearer " + (await this.getToken()).id_token,
357
- ...headers
358
- })
363
+ headers: new Headers(headers)
359
364
  });
360
365
  }
361
366
  async getUser() {
@@ -632,7 +637,7 @@ mutation addPendingDocumentMutation(
632
637
  }
633
638
  }`, { variables: { collection, relativePath } });
634
639
  }
635
- async fetchCollection(collectionName, includeDocuments, after, sortKey, order, filterArgs) {
640
+ async fetchCollection(collectionName, includeDocuments, folder = "", after, sortKey, order, filterArgs) {
636
641
  let filter = null;
637
642
  const filterField = filterArgs == null ? void 0 : filterArgs.filterField;
638
643
  if (filterField) {
@@ -669,13 +674,13 @@ mutation addPendingDocumentMutation(
669
674
  if (includeDocuments === true) {
670
675
  const sort = sortKey || this.schema.getIsTitleFieldName(collectionName);
671
676
  const response = order === "asc" ? await this.api.request(`#graphql
672
- query($collection: String!, $includeDocuments: Boolean!, $sort: String, $limit: Float, $after: String, $filter: DocumentFilter){
677
+ query($collection: String!, $includeDocuments: Boolean!, $sort: String, $limit: Float, $after: String, $filter: DocumentFilter, $folder: String){
673
678
  collection(collection: $collection){
674
679
  name
675
680
  label
676
681
  format
677
682
  templates
678
- documents(sort: $sort, after: $after, first: $limit, filter: $filter) @include(if: $includeDocuments) {
683
+ documents(sort: $sort, after: $after, first: $limit, filter: $filter, folder: $folder) @include(if: $includeDocuments) {
679
684
  totalCount
680
685
  pageInfo {
681
686
  hasPreviousPage
@@ -685,6 +690,11 @@ mutation addPendingDocumentMutation(
685
690
  }
686
691
  edges {
687
692
  node {
693
+ __typename
694
+ ... on Folder {
695
+ name
696
+ path
697
+ }
688
698
  ... on Document {
689
699
  _sys {
690
700
  title
@@ -705,19 +715,20 @@ mutation addPendingDocumentMutation(
705
715
  variables: {
706
716
  collection: collectionName,
707
717
  includeDocuments,
718
+ folder,
708
719
  sort,
709
720
  limit: 50,
710
721
  after,
711
722
  filter
712
723
  }
713
724
  }) : await this.api.request(`#graphql
714
- query($collection: String!, $includeDocuments: Boolean!, $sort: String, $limit: Float, $after: String, $filter: DocumentFilter){
725
+ query($collection: String!, $includeDocuments: Boolean!, $sort: String, $limit: Float, $after: String, $filter: DocumentFilter, $folder: String) {
715
726
  collection(collection: $collection){
716
727
  name
717
728
  label
718
729
  format
719
730
  templates
720
- documents(sort: $sort, before: $after, last: $limit, filter: $filter) @include(if: $includeDocuments) {
731
+ documents(sort: $sort, before: $after, last: $limit, filter: $filter, folder: $folder) @include(if: $includeDocuments) {
721
732
  totalCount
722
733
  pageInfo {
723
734
  hasPreviousPage
@@ -727,6 +738,11 @@ mutation addPendingDocumentMutation(
727
738
  }
728
739
  edges {
729
740
  node {
741
+ __typename
742
+ ... on Folder {
743
+ name
744
+ path
745
+ }
730
746
  ... on Document {
731
747
  _sys {
732
748
  title
@@ -747,6 +763,7 @@ mutation addPendingDocumentMutation(
747
763
  variables: {
748
764
  collection: collectionName,
749
765
  includeDocuments,
766
+ folder,
750
767
  sort,
751
768
  limit: 50,
752
769
  after,
@@ -1479,6 +1496,9 @@ mutation addPendingDocumentMutation(
1479
1496
  .tina-tailwind .flex-shrink-0 {
1480
1497
  flex-shrink: 0;
1481
1498
  }
1499
+ .tina-tailwind .shrink-0 {
1500
+ flex-shrink: 0;
1501
+ }
1482
1502
  .tina-tailwind .flex-grow-0 {
1483
1503
  flex-grow: 0;
1484
1504
  }
@@ -1541,6 +1561,9 @@ mutation addPendingDocumentMutation(
1541
1561
  .tina-tailwind .items-stretch {
1542
1562
  align-items: stretch;
1543
1563
  }
1564
+ .tina-tailwind .justify-start {
1565
+ justify-content: flex-start;
1566
+ }
1544
1567
  .tina-tailwind .justify-end {
1545
1568
  justify-content: flex-end;
1546
1569
  }
@@ -1556,6 +1579,9 @@ mutation addPendingDocumentMutation(
1556
1579
  .tina-tailwind .gap-0\\.5 {
1557
1580
  gap: 2px;
1558
1581
  }
1582
+ .tina-tailwind .gap-1 {
1583
+ gap: 4px;
1584
+ }
1559
1585
  .tina-tailwind .gap-2 {
1560
1586
  gap: 8px;
1561
1587
  }
@@ -1616,9 +1642,15 @@ mutation addPendingDocumentMutation(
1616
1642
  .tina-tailwind .border {
1617
1643
  border-width: 1px;
1618
1644
  }
1645
+ .tina-tailwind .border-0 {
1646
+ border-width: 0;
1647
+ }
1619
1648
  .tina-tailwind .border-b {
1620
1649
  border-bottom-width: 1px;
1621
1650
  }
1651
+ .tina-tailwind .border-r {
1652
+ border-right-width: 1px;
1653
+ }
1622
1654
  .tina-tailwind .border-gray-100 {
1623
1655
  --tw-border-opacity: 1;
1624
1656
  border-color: rgb(237 236 243 / var(--tw-border-opacity));
@@ -1643,6 +1675,12 @@ mutation addPendingDocumentMutation(
1643
1675
  --tw-bg-opacity: 1;
1644
1676
  background-color: rgb(246 246 249 / var(--tw-bg-opacity));
1645
1677
  }
1678
+ .tina-tailwind .bg-gray-50\\/30 {
1679
+ background-color: rgb(246 246 249 / .3);
1680
+ }
1681
+ .tina-tailwind .bg-transparent {
1682
+ background-color: transparent;
1683
+ }
1646
1684
  .tina-tailwind .bg-white {
1647
1685
  --tw-bg-opacity: 1;
1648
1686
  background-color: rgb(255 255 255 / var(--tw-bg-opacity));
@@ -1684,6 +1722,9 @@ mutation addPendingDocumentMutation(
1684
1722
  .tina-tailwind .fill-current {
1685
1723
  fill: currentColor;
1686
1724
  }
1725
+ .tina-tailwind .p-0 {
1726
+ padding: 0px;
1727
+ }
1687
1728
  .tina-tailwind .px-12 {
1688
1729
  padding-left: 48px;
1689
1730
  padding-right: 48px;
@@ -1752,6 +1793,12 @@ mutation addPendingDocumentMutation(
1752
1793
  .tina-tailwind .pl-8 {
1753
1794
  padding-left: 32px;
1754
1795
  }
1796
+ .tina-tailwind .pr-0 {
1797
+ padding-right: 0px;
1798
+ }
1799
+ .tina-tailwind .pr-0\\.5 {
1800
+ padding-right: 2px;
1801
+ }
1755
1802
  .tina-tailwind .pr-3 {
1756
1803
  padding-right: 12px;
1757
1804
  }
@@ -1822,6 +1869,10 @@ mutation addPendingDocumentMutation(
1822
1869
  .tina-tailwind .tracking-wide {
1823
1870
  letter-spacing: 0.025em;
1824
1871
  }
1872
+ .tina-tailwind .text-blue-400 {
1873
+ --tw-text-opacity: 1;
1874
+ color: rgb(34 150 254 / var(--tw-text-opacity));
1875
+ }
1825
1876
  .tina-tailwind .text-blue-500 {
1826
1877
  --tw-text-opacity: 1;
1827
1878
  color: rgb(0 132 255 / var(--tw-text-opacity));
@@ -1833,6 +1884,10 @@ mutation addPendingDocumentMutation(
1833
1884
  .tina-tailwind .text-current {
1834
1885
  color: currentColor;
1835
1886
  }
1887
+ .tina-tailwind .text-gray-200 {
1888
+ --tw-text-opacity: 1;
1889
+ color: rgb(225 221 236 / var(--tw-text-opacity));
1890
+ }
1836
1891
  .tina-tailwind .text-gray-300 {
1837
1892
  --tw-text-opacity: 1;
1838
1893
  color: rgb(178 173 190 / var(--tw-text-opacity));
@@ -1853,10 +1908,6 @@ mutation addPendingDocumentMutation(
1853
1908
  --tw-text-opacity: 1;
1854
1909
  color: rgb(67 62 82 / var(--tw-text-opacity));
1855
1910
  }
1856
- .tina-tailwind .text-gray-800 {
1857
- --tw-text-opacity: 1;
1858
- color: rgb(54 49 69 / var(--tw-text-opacity));
1859
- }
1860
1911
  .tina-tailwind .text-gray-900 {
1861
1912
  --tw-text-opacity: 1;
1862
1913
  color: rgb(37 35 54 / var(--tw-text-opacity));
@@ -1876,6 +1927,15 @@ mutation addPendingDocumentMutation(
1876
1927
  .tina-tailwind .underline {
1877
1928
  text-decoration-line: underline;
1878
1929
  }
1930
+ .tina-tailwind .decoration-blue-200 {
1931
+ text-decoration-color: #85C5FE;
1932
+ }
1933
+ .tina-tailwind .decoration-1 {
1934
+ text-decoration-thickness: 1px;
1935
+ }
1936
+ .tina-tailwind .underline-offset-2 {
1937
+ text-underline-offset: 2px;
1938
+ }
1879
1939
  .tina-tailwind .opacity-0 {
1880
1940
  opacity: 0;
1881
1941
  }
@@ -1987,14 +2047,24 @@ mutation addPendingDocumentMutation(
1987
2047
  --tw-bg-opacity: 1;
1988
2048
  background-color: rgb(5 116 228 / var(--tw-bg-opacity));
1989
2049
  }
2050
+ .tina-tailwind .hover\\:bg-gray-50\\/50:hover {
2051
+ background-color: rgb(246 246 249 / .5);
2052
+ }
1990
2053
  .tina-tailwind .hover\\:text-blue-400:hover {
1991
2054
  --tw-text-opacity: 1;
1992
2055
  color: rgb(34 150 254 / var(--tw-text-opacity));
1993
2056
  }
2057
+ .tina-tailwind .hover\\:text-blue-500:hover {
2058
+ --tw-text-opacity: 1;
2059
+ color: rgb(0 132 255 / var(--tw-text-opacity));
2060
+ }
1994
2061
  .tina-tailwind .hover\\:text-blue-600:hover {
1995
2062
  --tw-text-opacity: 1;
1996
2063
  color: rgb(5 116 228 / var(--tw-text-opacity));
1997
2064
  }
2065
+ .tina-tailwind .hover\\:decoration-blue-400:hover {
2066
+ text-decoration-color: #2296fe;
2067
+ }
1998
2068
  .tina-tailwind .hover\\:opacity-100:hover {
1999
2069
  opacity: 1;
2000
2070
  }
@@ -2578,12 +2648,24 @@ This will work when developing locally but NOT when deployed to production.
2578
2648
  function IoMdClose(props) {
2579
2649
  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);
2580
2650
  }
2651
+ function BiArrowBack(props) {
2652
+ 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);
2653
+ }
2654
+ function BiCopy(props) {
2655
+ 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);
2656
+ }
2581
2657
  function BiEdit(props) {
2582
2658
  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);
2583
2659
  }
2584
2660
  function BiError(props) {
2585
2661
  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);
2586
2662
  }
2663
+ function BiFile(props) {
2664
+ 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);
2665
+ }
2666
+ function BiFolder(props) {
2667
+ 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);
2668
+ }
2587
2669
  function BiLogIn(props) {
2588
2670
  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);
2589
2671
  }
@@ -2642,7 +2724,7 @@ This will work when developing locally but NOT when deployed to production.
2642
2724
  }),
2643
2725
  RenderNavCollection: ({ collection }) => /* @__PURE__ */ React__default["default"].createElement(SidebarLink, {
2644
2726
  label: collection.label ? collection.label : collection.name,
2645
- to: `/collections/${collection.name}`,
2727
+ to: `/collections/${collection.name}/~`,
2646
2728
  Icon: ImFilesEmpty
2647
2729
  })
2648
2730
  }), !renderDesktopNav && /* @__PURE__ */ React__default["default"].createElement(react.Transition, {
@@ -2679,7 +2761,7 @@ This will work when developing locally but NOT when deployed to production.
2679
2761
  }),
2680
2762
  RenderNavCollection: ({ collection }) => /* @__PURE__ */ React__default["default"].createElement(SidebarLink, {
2681
2763
  label: collection.label ? collection.label : collection.name,
2682
- to: `/collections/${collection.name}`,
2764
+ to: `/collections/${collection.name}/~`,
2683
2765
  Icon: ImFilesEmpty,
2684
2766
  onClick: () => {
2685
2767
  setMenuIsOpen(false);
@@ -2917,6 +2999,9 @@ This will work when developing locally but NOT when deployed to production.
2917
2999
  }, "Welcome to Tina!")), /* @__PURE__ */ React__default["default"].createElement(PageBodyNarrow, null, "This is your dashboard for editing or creating content. Select a collection on the left to begin.")));
2918
3000
  });
2919
3001
  };
3002
+ function RiHome2Line(props) {
3003
+ 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);
3004
+ }
2920
3005
  const LoadingPage = () => /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null, /* @__PURE__ */ React__default["default"].createElement("div", {
2921
3006
  style: {
2922
3007
  position: "absolute",
@@ -3035,7 +3120,7 @@ This will work when developing locally but NOT when deployed to production.
3035
3120
  className: "w-7 h-auto fill-current opacity-70 mr-1"
3036
3121
  }), " Reload"));
3037
3122
  };
3038
- const useGetCollection = (cms, collectionName, includeDocuments = true, after = "", sortKey, filterArgs) => {
3123
+ const useGetCollection = (cms, collectionName, includeDocuments = true, folder, after = "", sortKey, filterArgs) => {
3039
3124
  const api = new TinaAdminApi(cms);
3040
3125
  const schema = cms.api.tina.schema;
3041
3126
  const collectionExtra = schema.getCollection(collectionName);
@@ -3044,13 +3129,14 @@ This will work when developing locally but NOT when deployed to production.
3044
3129
  const [error, setError] = React.useState(void 0);
3045
3130
  const [resetState, setResetSate] = React.useState(0);
3046
3131
  React.useEffect(() => {
3132
+ let cancelled = false;
3047
3133
  const fetchCollection = async () => {
3048
3134
  var _a;
3049
- if (await api.isAuthenticated()) {
3135
+ if (await api.isAuthenticated() && !folder.loading && !cancelled) {
3050
3136
  const { name, order } = JSON.parse(sortKey || "{}");
3051
3137
  const validSortKey = ((_a = collectionExtra.fields) == null ? void 0 : _a.map((x) => x.name).includes(name)) ? name : void 0;
3052
3138
  try {
3053
- const collection2 = await api.fetchCollection(collectionName, includeDocuments, after, validSortKey, order, filterArgs);
3139
+ const collection2 = await api.fetchCollection(collectionName, includeDocuments, (filterArgs == null ? void 0 : filterArgs.filterField) ? "" : folder.fullyQualifiedName, after, validSortKey, order, filterArgs);
3054
3140
  setCollection(collection2);
3055
3141
  } catch (error2) {
3056
3142
  cms.alerts.error(`[${error2.name}] GetCollection failed: ${error2.message}`);
@@ -3061,15 +3147,29 @@ This will work when developing locally but NOT when deployed to production.
3061
3147
  setLoading(false);
3062
3148
  }
3063
3149
  };
3150
+ if (cancelled)
3151
+ return;
3064
3152
  setLoading(true);
3065
3153
  fetchCollection();
3066
- }, [cms, collectionName, resetState, after, sortKey]);
3154
+ return () => {
3155
+ cancelled = true;
3156
+ };
3157
+ }, [
3158
+ cms,
3159
+ collectionName,
3160
+ folder.loading,
3161
+ folder.fullyQualifiedName,
3162
+ resetState,
3163
+ after,
3164
+ sortKey
3165
+ ]);
3067
3166
  const reFetchCollection = () => setResetSate((x) => x + 1);
3068
3167
  return { collection, loading, error, reFetchCollection, collectionExtra };
3069
3168
  };
3070
3169
  const GetCollection = ({
3071
3170
  cms,
3072
3171
  collectionName,
3172
+ folder,
3073
3173
  includeDocuments = true,
3074
3174
  startCursor,
3075
3175
  sortKey,
@@ -3077,7 +3177,7 @@ This will work when developing locally but NOT when deployed to production.
3077
3177
  filterArgs
3078
3178
  }) => {
3079
3179
  const navigate = reactRouterDom.useNavigate();
3080
- const { collection, loading, error, reFetchCollection, collectionExtra } = useGetCollection(cms, collectionName, includeDocuments, startCursor || "", sortKey, filterArgs) || {};
3180
+ const { collection, loading, error, reFetchCollection, collectionExtra } = useGetCollection(cms, collectionName, includeDocuments, folder, startCursor || "", sortKey, filterArgs) || {};
3081
3181
  React.useEffect(() => {
3082
3182
  var _a, _b, _c, _d, _e, _f, _g, _h;
3083
3183
  if (loading)
@@ -3087,7 +3187,11 @@ This will work when developing locally but NOT when deployed to production.
3087
3187
  const allowDelete = (_f = (_e = (_d = collectionDefinition == null ? void 0 : collectionDefinition.ui) == null ? void 0 : _d.allowedActions) == null ? void 0 : _e.delete) != null ? _f : true;
3088
3188
  if (!allowCreate && !allowDelete && ((_h = (_g = collection.documents) == null ? void 0 : _g.edges) == null ? void 0 : _h.length) === 1) {
3089
3189
  const doc = collection.documents.edges[0].node;
3090
- handleNavigate(navigate, cms, collection, collectionDefinition, doc);
3190
+ const pathToDoc = doc._sys.breadcrumbs;
3191
+ if (folder.fullyQualifiedName) {
3192
+ pathToDoc.unshift("~");
3193
+ }
3194
+ navigate(`/${["collections", "edit", collectionName, ...pathToDoc].join("/")}`, { replace: true });
3091
3195
  }
3092
3196
  }, [(collection == null ? void 0 : collection.name) || "", loading]);
3093
3197
  if (error) {
@@ -3098,6 +3202,42 @@ This will work when developing locally but NOT when deployed to production.
3098
3202
  }
3099
3203
  return /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null, children(collection, loading, reFetchCollection, collectionExtra));
3100
3204
  };
3205
+ const folderRegex = /^.*\/~\/*(.*)$/;
3206
+ const parentFolder = (folder) => {
3207
+ return {
3208
+ ...folder,
3209
+ name: folder.name.split("/").slice(0, -1).join("/"),
3210
+ fullyQualifiedName: folder.fullyQualifiedName.split("/").slice(0, -1).join("/"),
3211
+ parentName: folder.parentName.split("/").slice(0, -1).join("/")
3212
+ };
3213
+ };
3214
+ const useCollectionFolder = () => {
3215
+ const [folder, setFolder] = React.useState({
3216
+ loading: true,
3217
+ name: "",
3218
+ fullyQualifiedName: "",
3219
+ parentName: ""
3220
+ });
3221
+ const loc = reactRouterDom.useLocation();
3222
+ React.useEffect(() => {
3223
+ const match = loc.pathname.match(folderRegex);
3224
+ const update = {
3225
+ name: match ? match[1] : "",
3226
+ fullyQualifiedName: match ? match[1] ? `~/${match[1]}` : "~" : "",
3227
+ loading: false,
3228
+ parentName: ""
3229
+ };
3230
+ if (update.fullyQualifiedName) {
3231
+ const pathParts = update.fullyQualifiedName.split("/");
3232
+ update.parentName = `/${pathParts.slice(0, pathParts.length - 1).join("/")}`;
3233
+ }
3234
+ setFolder({
3235
+ ...folder,
3236
+ ...update
3237
+ });
3238
+ }, [loc]);
3239
+ return folder;
3240
+ };
3101
3241
  const LOCAL_STORAGE_KEY = "tinacms.admin.collection.list.page";
3102
3242
  const isSSR = typeof window === "undefined";
3103
3243
  const TemplateMenu = ({ templates }) => {
@@ -3117,14 +3257,14 @@ This will work when developing locally but NOT when deployed to production.
3117
3257
  leaveFrom: "transform opacity-100 scale-100",
3118
3258
  leaveTo: "transform opacity-0 scale-95"
3119
3259
  }, /* @__PURE__ */ React__default["default"].createElement(react.Menu.Items, {
3120
- className: "origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none"
3260
+ className: "origin-top-right absolute right-0 mt-2 z-menu w-56 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none"
3121
3261
  }, /* @__PURE__ */ React__default["default"].createElement("div", {
3122
3262
  className: "py-1"
3123
3263
  }, templates.map((template) => /* @__PURE__ */ React__default["default"].createElement(react.Menu.Item, {
3124
3264
  key: `${template.label}-${template.name}`
3125
3265
  }, ({ active }) => /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Link, {
3126
3266
  to: `${template.name}/new`,
3127
- className: `w-full text-md px-4 py-2 tracking-wide flex items-center opacity-80 text-gray-600 ${active && "text-gray-800 opacity-100"}`
3267
+ className: `w-full text-md px-4 py-2 tracking-wide flex items-center transition ease-out duration-100 ${active ? "text-blue-600 opacity-100 bg-gray-50" : "opacity-80 text-gray-600"}`
3128
3268
  }, template.label))))))));
3129
3269
  };
3130
3270
  const handleNavigate = (navigate, cms, collection, collectionDefinition, document) => {
@@ -3143,7 +3283,8 @@ This will work when developing locally but NOT when deployed to production.
3143
3283
  tinaPreview ? navigate(`/~/${routeOverride}`) : window.location.href = routeOverride;
3144
3284
  return null;
3145
3285
  } else {
3146
- navigate(document._sys.breadcrumbs.join("/"));
3286
+ const pathToDoc = document._sys.breadcrumbs;
3287
+ navigate(`/${["collections", "edit", collection.name, ...pathToDoc].join("/")}`, { replace: true });
3147
3288
  }
3148
3289
  };
3149
3290
  const CollectionListPage = () => {
@@ -3162,15 +3303,17 @@ This will work when developing locally but NOT when deployed to production.
3162
3303
  after: "",
3163
3304
  booleanEquals: null
3164
3305
  });
3306
+ const [activeSearch, setActiveSearch] = React__default["default"].useState(false);
3165
3307
  const [endCursor, setEndCursor] = React.useState("");
3166
3308
  const [prevCursors, setPrevCursors] = React.useState([]);
3167
3309
  const [sortKey, setSortKey] = React.useState(isSSR ? "" : window.localStorage.getItem(`${LOCAL_STORAGE_KEY}.${collectionName}`) || JSON.stringify({
3168
3310
  order: "asc",
3169
3311
  name: ""
3170
3312
  }));
3171
- const { order = "asc" } = JSON.parse(sortKey || "{}");
3313
+ const { order = "asc", name: sortName } = JSON.parse(sortKey || "{}");
3172
3314
  const [sortOrder, setSortOrder] = React.useState(order);
3173
3315
  const loc = reactRouterDom.useLocation();
3316
+ const folder = useCollectionFolder();
3174
3317
  React.useEffect(() => {
3175
3318
  setSortKey(window.localStorage.getItem(`${LOCAL_STORAGE_KEY}.${collectionName}`) || JSON.stringify({
3176
3319
  order: "asc",
@@ -3200,6 +3343,7 @@ This will work when developing locally but NOT when deployed to production.
3200
3343
  includeDocuments: true,
3201
3344
  startCursor: endCursor,
3202
3345
  sortKey,
3346
+ folder,
3203
3347
  filterArgs: collectionName === vars.collection ? vars : {
3204
3348
  collection: collectionName,
3205
3349
  relativePath: "",
@@ -3218,6 +3362,7 @@ This will work when developing locally but NOT when deployed to production.
3218
3362
  const admin = cms.api.admin;
3219
3363
  const pageInfo = collection.documents.pageInfo;
3220
3364
  const fields = (_a = collectionExtra.fields) == null ? void 0 : _a.filter((x) => ["string", "number", "datetime", "boolean"].includes(x.type));
3365
+ const sortField = fields.find((field) => field.name === sortName);
3221
3366
  const filterFields = (_b = collectionExtra.fields) == null ? void 0 : _b.filter((x) => {
3222
3367
  return ["string", "datetime", "boolean"].includes(x.type) && !x.list;
3223
3368
  });
@@ -3228,6 +3373,7 @@ This will work when developing locally but NOT when deployed to production.
3228
3373
  const collectionDefinition = cms.api.tina.schema.getCollection(collection.name);
3229
3374
  const allowCreate = (_e = (_d = (_c = collectionDefinition == null ? void 0 : collectionDefinition.ui) == null ? void 0 : _c.allowedActions) == null ? void 0 : _d.create) != null ? _e : true;
3230
3375
  const allowDelete = (_h = (_g = (_f = collectionDefinition == null ? void 0 : collectionDefinition.ui) == null ? void 0 : _f.allowedActions) == null ? void 0 : _g.delete) != null ? _h : true;
3376
+ const folderView = folder.fullyQualifiedName !== "";
3231
3377
  return /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null, deleteModalOpen && /* @__PURE__ */ React__default["default"].createElement(DeleteModal, {
3232
3378
  filename: vars.relativePath,
3233
3379
  deleteFunc: async () => {
@@ -3275,9 +3421,9 @@ This will work when developing locally but NOT when deployed to production.
3275
3421
  className: "flex flex-col gap-4"
3276
3422
  }, /* @__PURE__ */ React__default["default"].createElement("h3", {
3277
3423
  className: "font-sans text-2xl text-gray-700"
3278
- }, collection.label ? collection.label : collection.name), (fields == null ? void 0 : fields.length) > 0 && /* @__PURE__ */ React__default["default"].createElement("div", {
3424
+ }, collection.label ? collection.label : collection.name), /* @__PURE__ */ React__default["default"].createElement("div", {
3279
3425
  className: "flex gap-4 items-end flex-wrap"
3280
- }, /* @__PURE__ */ React__default["default"].createElement("div", {
3426
+ }, (fields == null ? void 0 : fields.length) > 0 && /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null, /* @__PURE__ */ React__default["default"].createElement("div", {
3281
3427
  className: "flex flex-col gap-2 items-start"
3282
3428
  }, /* @__PURE__ */ React__default["default"].createElement("label", {
3283
3429
  htmlFor: "sort",
@@ -3440,6 +3586,7 @@ This will work when developing locally but NOT when deployed to production.
3440
3586
  className: "flex gap-3"
3441
3587
  }, /* @__PURE__ */ React__default["default"].createElement(toolkit.Button, {
3442
3588
  onClick: () => {
3589
+ setActiveSearch(true);
3443
3590
  setEndCursor("");
3444
3591
  setPrevCursors([]);
3445
3592
  reFetchCollection();
@@ -3450,8 +3597,10 @@ This will work when developing locally but NOT when deployed to production.
3450
3597
  className: "w-5 h-full ml-1.5 opacity-70"
3451
3598
  })), (vars.startsWith || vars.after || vars.before || vars.booleanEquals) && /* @__PURE__ */ React__default["default"].createElement(toolkit.Button, {
3452
3599
  onClick: () => {
3600
+ setActiveSearch(false);
3453
3601
  setVars((old) => ({
3454
3602
  ...old,
3603
+ filterField: "",
3455
3604
  startsWith: "",
3456
3605
  after: "",
3457
3606
  before: "",
@@ -3464,10 +3613,16 @@ This will work when developing locally but NOT when deployed to production.
3464
3613
  variant: "white"
3465
3614
  }, "Clear", " ", /* @__PURE__ */ React__default["default"].createElement(BiX, {
3466
3615
  className: "w-5 h-full ml-1 opacity-70"
3467
- })))))), /* @__PURE__ */ React__default["default"].createElement("div", {
3616
+ }))))))), /* @__PURE__ */ React__default["default"].createElement("div", {
3468
3617
  className: "flex self-end justify-self-end"
3469
3618
  }, !collection.templates && allowCreate && /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Link, {
3470
- to: `new`,
3619
+ to: `/${folder.fullyQualifiedName ? [
3620
+ "collections",
3621
+ "new",
3622
+ collectionName,
3623
+ "~",
3624
+ folder.name
3625
+ ].join("/") : ["collections", "new", collectionName].join("/")}`,
3471
3626
  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"
3472
3627
  }, "Create New", " ", /* @__PURE__ */ React__default["default"].createElement(BiPlus, {
3473
3628
  className: "w-5 h-full ml-1 opacity-70"
@@ -3475,25 +3630,73 @@ This will work when developing locally but NOT when deployed to production.
3475
3630
  templates: collection.templates
3476
3631
  })))), /* @__PURE__ */ React__default["default"].createElement(PageBody, null, /* @__PURE__ */ React__default["default"].createElement("div", {
3477
3632
  className: "w-full mx-auto max-w-screen-xl"
3478
- }, documents.length > 0 ? /* @__PURE__ */ React__default["default"].createElement("table", {
3633
+ }, sortField && !sortField.required && /* @__PURE__ */ React__default["default"].createElement("p", {
3634
+ className: "mb-4 text-gray-500"
3635
+ }, /* @__PURE__ */ React__default["default"].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__default["default"].createElement("table", {
3479
3636
  className: "table-auto shadow bg-white border-b border-gray-200 w-full max-w-full rounded-lg"
3480
3637
  }, /* @__PURE__ */ React__default["default"].createElement("tbody", {
3481
3638
  className: "divide-y divide-gray-150"
3482
- }, documents.map((document) => {
3639
+ }, !activeSearch && folder.name && /* @__PURE__ */ React__default["default"].createElement("tr", null, /* @__PURE__ */ React__default["default"].createElement("td", {
3640
+ colSpan: 5
3641
+ }, /* @__PURE__ */ React__default["default"].createElement(Breadcrumb, {
3642
+ folder,
3643
+ navigate,
3644
+ collectionName
3645
+ }))), documents.map((document) => {
3483
3646
  var _a2;
3647
+ if (document.node.__typename === "Folder") {
3648
+ return /* @__PURE__ */ React__default["default"].createElement("tr", {
3649
+ key: `folder-${document.node.path}`
3650
+ }, /* @__PURE__ */ React__default["default"].createElement("td", {
3651
+ className: "pl-5 pr-3 py-3 truncate max-w-0"
3652
+ }, /* @__PURE__ */ React__default["default"].createElement("a", {
3653
+ className: "text-blue-600 hover:text-blue-400 flex items-center gap-3 cursor-pointer truncate",
3654
+ onClick: () => {
3655
+ navigate(`/${[
3656
+ "collections",
3657
+ collectionName,
3658
+ document.node.path
3659
+ ].join("/")}`, { replace: true });
3660
+ }
3661
+ }, /* @__PURE__ */ React__default["default"].createElement(BiFolder, {
3662
+ className: "inline-block h-6 w-auto flex-shrink-0 opacity-70"
3663
+ }), /* @__PURE__ */ React__default["default"].createElement("span", {
3664
+ className: "truncate block"
3665
+ }, /* @__PURE__ */ React__default["default"].createElement("span", {
3666
+ className: "block text-xs text-gray-400 mb-1 uppercase"
3667
+ }, "Name"), /* @__PURE__ */ React__default["default"].createElement("span", {
3668
+ className: "h-5 leading-5 block truncate"
3669
+ }, /* @__PURE__ */ React__default["default"].createElement("span", null, document.node.name))))), /* @__PURE__ */ React__default["default"].createElement("td", {
3670
+ className: "px-3 py-3 truncate max-w-0",
3671
+ colSpan: 4
3672
+ }, /* @__PURE__ */ React__default["default"].createElement("span", {
3673
+ className: "block text-xs text-gray-400 mb-1 uppercase"
3674
+ }, "Path"), /* @__PURE__ */ React__default["default"].createElement("span", {
3675
+ className: "leading-5 block text-sm font-medium text-gray-900 truncate"
3676
+ }, document.node.path.substring(2).split("/").map((node) => {
3677
+ return /* @__PURE__ */ React__default["default"].createElement("span", {
3678
+ key: node
3679
+ }, /* @__PURE__ */ React__default["default"].createElement("span", {
3680
+ className: "text-gray-300 pr-0.5"
3681
+ }, "/"), /* @__PURE__ */ React__default["default"].createElement("span", {
3682
+ className: "pr-0.5"
3683
+ }, node));
3684
+ }))));
3685
+ }
3484
3686
  const hasTitle = Boolean(document.node._sys.title);
3485
3687
  const subfolders = document.node._sys.breadcrumbs.slice(0, -1).join("/");
3486
3688
  return /* @__PURE__ */ React__default["default"].createElement("tr", {
3487
3689
  key: `document-${document.node._sys.relativePath}`,
3488
3690
  className: ""
3489
3691
  }, /* @__PURE__ */ React__default["default"].createElement("td", {
3490
- className: "pl-5 pr-3 py-2 truncate max-w-0"
3692
+ className: "pl-5 pr-3 py-3 truncate max-w-0",
3693
+ colSpan: hasTitle ? 1 : 2
3491
3694
  }, /* @__PURE__ */ React__default["default"].createElement("a", {
3492
3695
  className: "text-blue-600 hover:text-blue-400 flex items-center gap-3 cursor-pointer truncate",
3493
3696
  onClick: () => {
3494
3697
  handleNavigate(navigate, cms, collection, collectionDefinition, document.node);
3495
3698
  }
3496
- }, /* @__PURE__ */ React__default["default"].createElement(BiEdit, {
3699
+ }, /* @__PURE__ */ React__default["default"].createElement(BiFile, {
3497
3700
  className: "inline-block h-6 w-auto flex-shrink-0 opacity-70"
3498
3701
  }), /* @__PURE__ */ React__default["default"].createElement("span", {
3499
3702
  className: "truncate block"
@@ -3501,24 +3704,24 @@ This will work when developing locally but NOT when deployed to production.
3501
3704
  className: "block text-xs text-gray-400 mb-1 uppercase"
3502
3705
  }, hasTitle ? "Title" : "Filename"), /* @__PURE__ */ React__default["default"].createElement("span", {
3503
3706
  className: "h-5 leading-5 block truncate"
3504
- }, !hasTitle && subfolders && /* @__PURE__ */ React__default["default"].createElement("span", {
3707
+ }, !folderView && !hasTitle && subfolders && /* @__PURE__ */ React__default["default"].createElement("span", {
3505
3708
  className: "text-xs text-gray-400"
3506
3709
  }, `${subfolders}/`), /* @__PURE__ */ React__default["default"].createElement("span", null, hasTitle ? (_a2 = document.node._sys) == null ? void 0 : _a2.title : document.node._sys.filename))))), hasTitle && /* @__PURE__ */ React__default["default"].createElement("td", {
3507
- className: "px-3 py-4 truncate max-w-0 "
3710
+ className: "px-3 py-3 truncate max-w-0"
3508
3711
  }, /* @__PURE__ */ React__default["default"].createElement("span", {
3509
3712
  className: "block text-xs text-gray-400 mb-1 uppercase"
3510
3713
  }, "Filename"), /* @__PURE__ */ React__default["default"].createElement("span", {
3511
3714
  className: "h-5 leading-5 block text-sm font-medium text-gray-900 truncate"
3512
- }, subfolders && /* @__PURE__ */ React__default["default"].createElement("span", {
3715
+ }, !folderView && subfolders && /* @__PURE__ */ React__default["default"].createElement("span", {
3513
3716
  className: "text-xs text-gray-400"
3514
3717
  }, `${subfolders}/`), /* @__PURE__ */ React__default["default"].createElement("span", null, document.node._sys.filename))), /* @__PURE__ */ React__default["default"].createElement("td", {
3515
- className: "px-3 py-4 truncate w-[15%]"
3718
+ className: "px-3 py-3 truncate w-[15%]"
3516
3719
  }, /* @__PURE__ */ React__default["default"].createElement("span", {
3517
3720
  className: "block text-xs text-gray-400 mb-1 uppercase"
3518
3721
  }, "Extension"), /* @__PURE__ */ React__default["default"].createElement("span", {
3519
3722
  className: "h-5 leading-5 block text-sm font-medium text-gray-900"
3520
3723
  }, document.node._sys.extension)), /* @__PURE__ */ React__default["default"].createElement("td", {
3521
- className: "px-3 py-4 truncate w-[15%]"
3724
+ className: "px-3 py-3 truncate w-[15%]"
3522
3725
  }, /* @__PURE__ */ React__default["default"].createElement("span", {
3523
3726
  className: "block text-xs text-gray-400 mb-1 uppercase"
3524
3727
  }, "Template"), /* @__PURE__ */ React__default["default"].createElement("span", {
@@ -3534,7 +3737,35 @@ This will work when developing locally but NOT when deployed to production.
3534
3737
  size: "1.3rem"
3535
3738
  }),
3536
3739
  onMouseDown: () => {
3537
- navigate(`${document.node._sys.breadcrumbs.join("/")}`, { replace: true });
3740
+ const pathToDoc = document.node._sys.breadcrumbs;
3741
+ if (folder.fullyQualifiedName) {
3742
+ pathToDoc.unshift("~");
3743
+ }
3744
+ navigate(`/${[
3745
+ "collections",
3746
+ "edit",
3747
+ collectionName,
3748
+ ...pathToDoc
3749
+ ].join("/")}`, { replace: true });
3750
+ }
3751
+ },
3752
+ allowCreate && {
3753
+ name: "duplicate",
3754
+ label: "Duplicate",
3755
+ Icon: /* @__PURE__ */ React__default["default"].createElement(BiCopy, {
3756
+ size: "1.3rem"
3757
+ }),
3758
+ onMouseDown: () => {
3759
+ const pathToDoc = document.node._sys.breadcrumbs;
3760
+ if (folder.fullyQualifiedName) {
3761
+ pathToDoc.unshift("~");
3762
+ }
3763
+ navigate(`/${[
3764
+ "collections",
3765
+ "duplicate",
3766
+ collectionName,
3767
+ ...pathToDoc
3768
+ ].join("/")}`, { replace: true });
3538
3769
  }
3539
3770
  },
3540
3771
  allowDelete && {
@@ -3596,6 +3827,51 @@ This will work when developing locally but NOT when deployed to production.
3596
3827
  }));
3597
3828
  });
3598
3829
  };
3830
+ const Breadcrumb = ({ folder, navigate, collectionName }) => {
3831
+ const folderArray = folder.name.split("/");
3832
+ return /* @__PURE__ */ React__default["default"].createElement("div", {
3833
+ className: "w-full bg-gray-50/30 flex items-stretch"
3834
+ }, /* @__PURE__ */ React__default["default"].createElement("button", {
3835
+ onClick: () => {
3836
+ const folders = folder.fullyQualifiedName.split("/");
3837
+ navigate(`/${[
3838
+ "collections",
3839
+ collectionName,
3840
+ ...folders.slice(0, folders.length - 1)
3841
+ ].join("/")}`, { replace: true });
3842
+ },
3843
+ 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"
3844
+ }, /* @__PURE__ */ React__default["default"].createElement(BiArrowBack, {
3845
+ className: "w-6 h-full opacity-70"
3846
+ })), /* @__PURE__ */ React__default["default"].createElement("span", {
3847
+ className: "px-3 py-2 text-gray-600 flex flex-wrap items-center justify-start gap-1"
3848
+ }, /* @__PURE__ */ React__default["default"].createElement("button", {
3849
+ onClick: () => {
3850
+ navigate(`/collections/${collectionName}/~`, {
3851
+ replace: true
3852
+ });
3853
+ },
3854
+ 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"
3855
+ }, /* @__PURE__ */ React__default["default"].createElement(RiHome2Line, {
3856
+ className: "w-5 h-auto"
3857
+ })), folderArray.map((node, index) => {
3858
+ return /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null, /* @__PURE__ */ React__default["default"].createElement("span", {
3859
+ className: "text-gray-200 shrink-0"
3860
+ }, "/"), index < folderArray.length - 1 ? /* @__PURE__ */ React__default["default"].createElement("button", {
3861
+ 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",
3862
+ onClick: () => {
3863
+ const folders = folder.fullyQualifiedName.split("/");
3864
+ navigate(`/${[
3865
+ "collections",
3866
+ collectionName,
3867
+ ...folders.slice(0, folders.length - (folders.length - (index + 2)))
3868
+ ].join("/")}`, { replace: true });
3869
+ }
3870
+ }, node) : /* @__PURE__ */ React__default["default"].createElement("span", {
3871
+ className: "whitespace-nowrap truncate"
3872
+ }, node));
3873
+ })));
3874
+ };
3599
3875
  const NoDocumentsPlaceholder = () => {
3600
3876
  return /* @__PURE__ */ React__default["default"].createElement("div", {
3601
3877
  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"
@@ -3658,10 +3934,10 @@ This will work when developing locally but NOT when deployed to production.
3658
3934
  function FaUnlock(props) {
3659
3935
  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);
3660
3936
  }
3661
- const createDocument = async (cms, collection, template, mutationInfo, values) => {
3937
+ const createDocument = async (cms, collection, template, mutationInfo, folder, values) => {
3662
3938
  const api = new TinaAdminApi(cms);
3663
3939
  const { filename, ...leftover } = values;
3664
- const relativePath = `${filename}.${collection.format}`;
3940
+ const relativePath = `${folder ? `${folder}/` : ""}${filename}.${collection.format}`;
3665
3941
  const params = api.schema.transformPayload(collection.name, {
3666
3942
  _collection: collection.name,
3667
3943
  ...template && { _template: template.name },
@@ -3677,10 +3953,12 @@ This will work when developing locally but NOT when deployed to production.
3677
3953
  }
3678
3954
  };
3679
3955
  const CollectionCreatePage = () => {
3956
+ const folder = useCollectionFolder();
3680
3957
  const { collectionName, templateName } = reactRouterDom.useParams();
3681
3958
  return /* @__PURE__ */ React__default["default"].createElement(GetCMS, null, (cms) => /* @__PURE__ */ React__default["default"].createElement(GetCollection, {
3682
3959
  cms,
3683
3960
  collectionName,
3961
+ folder,
3684
3962
  includeDocuments: false
3685
3963
  }, (collection) => {
3686
3964
  const mutationInfo = {
@@ -3691,7 +3969,8 @@ This will work when developing locally but NOT when deployed to production.
3691
3969
  cms,
3692
3970
  collection,
3693
3971
  templateName,
3694
- mutationInfo
3972
+ mutationInfo,
3973
+ folder
3695
3974
  });
3696
3975
  }));
3697
3976
  };
@@ -3713,7 +3992,14 @@ This will work when developing locally but NOT when deployed to production.
3713
3992
  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"}`
3714
3993
  }));
3715
3994
  };
3716
- const RenderForm$1 = ({ cms, collection, templateName, mutationInfo }) => {
3995
+ const RenderForm$1 = ({
3996
+ cms,
3997
+ collection,
3998
+ folder,
3999
+ templateName,
4000
+ mutationInfo,
4001
+ customDefaults
4002
+ }) => {
3717
4003
  var _a, _b, _c, _d, _e, _f;
3718
4004
  const navigate = reactRouterDom.useNavigate();
3719
4005
  const [formIsPristine, setFormIsPristine] = React.useState(true);
@@ -3739,7 +4025,7 @@ This will work when developing locally but NOT when deployed to production.
3739
4025
  };
3740
4026
  }
3741
4027
  }
3742
- const defaultItem = ((_d = template.ui) == null ? void 0 : _d.defaultItem) || (template == null ? void 0 : template.defaultItem);
4028
+ const defaultItem = customDefaults || ((_d = template.ui) == null ? void 0 : _d.defaultItem) || (template == null ? void 0 : template.defaultItem);
3743
4029
  const form = React.useMemo(() => {
3744
4030
  var _a2, _b2;
3745
4031
  return new toolkit.Form({
@@ -3796,9 +4082,12 @@ This will work when developing locally but NOT when deployed to production.
3796
4082
  ],
3797
4083
  onSubmit: async (values) => {
3798
4084
  try {
3799
- await createDocument(cms, collection, template, mutationInfo, values);
4085
+ const folderName = folder.fullyQualifiedName ? folder.name : "";
4086
+ await createDocument(cms, collection, template, mutationInfo, folderName, values);
3800
4087
  cms.alerts.success("Document created!");
3801
- navigate(`/collections/${collection.name}`);
4088
+ setTimeout(() => {
4089
+ navigate(`/collections/${collection.name}${folder.fullyQualifiedName ? `/${folder.fullyQualifiedName}` : ""}`);
4090
+ }, 10);
3802
4091
  } catch (error) {
3803
4092
  console.error(error);
3804
4093
  const defaultErrorText = "There was a problem saving your document.";
@@ -3825,7 +4114,7 @@ This will work when developing locally but NOT when deployed to production.
3825
4114
  }, /* @__PURE__ */ React__default["default"].createElement("span", {
3826
4115
  className: "block text-sm leading-tight uppercase text-gray-400 mb-1"
3827
4116
  }, /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Link, {
3828
- to: `/collections/${collection.name}`,
4117
+ to: `/collections/${collection.name}${folder.fullyQualifiedName ? `/${folder.fullyQualifiedName}` : ""}`,
3829
4118
  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"
3830
4119
  }, collection.label ? collection.label : collection.name), /* @__PURE__ */ React__default["default"].createElement(HiChevronRight, {
3831
4120
  className: "inline-block -mt-0.5 opacity-50"
@@ -3878,6 +4167,38 @@ This will work when developing locally but NOT when deployed to production.
3878
4167
  }
3879
4168
  return /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null, children(document, loading));
3880
4169
  };
4170
+ const CollectionDuplicatePage = () => {
4171
+ const folder = useCollectionFolder();
4172
+ const { collectionName, ...rest } = reactRouterDom.useParams();
4173
+ const { "*": filename } = rest;
4174
+ return /* @__PURE__ */ React__default["default"].createElement(GetCMS, null, (cms) => /* @__PURE__ */ React__default["default"].createElement(GetCollection, {
4175
+ cms,
4176
+ collectionName,
4177
+ folder,
4178
+ includeDocuments: false
4179
+ }, (collection) => {
4180
+ const relativePath = `${filename.startsWith("~/") ? filename.substring(2) : filename}.${collection.format}`;
4181
+ const mutationInfo = {
4182
+ includeCollection: true,
4183
+ includeTemplate: !!collection.templates
4184
+ };
4185
+ return /* @__PURE__ */ React__default["default"].createElement(GetDocument, {
4186
+ cms,
4187
+ collectionName: collection.name,
4188
+ relativePath
4189
+ }, (document) => {
4190
+ var _a;
4191
+ return /* @__PURE__ */ React__default["default"].createElement(RenderForm$1, {
4192
+ cms,
4193
+ collection,
4194
+ templateName: (_a = document._values) == null ? void 0 : _a._template,
4195
+ folder: parentFolder(folder),
4196
+ mutationInfo,
4197
+ customDefaults: document._values
4198
+ });
4199
+ });
4200
+ }));
4201
+ };
3881
4202
  const updateDocument = async (cms, relativePath, collection, mutationInfo, values) => {
3882
4203
  const api = new TinaAdminApi(cms);
3883
4204
  const params = api.schema.transformPayload(collection.name, values);
@@ -3892,13 +4213,16 @@ This will work when developing locally but NOT when deployed to production.
3892
4213
  };
3893
4214
  const CollectionUpdatePage = () => {
3894
4215
  const { collectionName, ...rest } = reactRouterDom.useParams();
4216
+ const folder = useCollectionFolder();
3895
4217
  const { "*": filename } = rest;
4218
+ const resolvedFile = folder.fullyQualifiedName ? folder.name : filename;
3896
4219
  return /* @__PURE__ */ React__default["default"].createElement(GetCMS, null, (cms) => /* @__PURE__ */ React__default["default"].createElement(GetCollection, {
3897
4220
  cms,
3898
4221
  collectionName,
4222
+ folder,
3899
4223
  includeDocuments: false
3900
4224
  }, (collection) => {
3901
- const relativePath = `${filename}.${collection.format}`;
4225
+ const relativePath = `${resolvedFile}.${collection.format}`;
3902
4226
  const mutationInfo = {
3903
4227
  includeCollection: true,
3904
4228
  includeTemplate: !!collection.templates
@@ -3910,7 +4234,7 @@ This will work when developing locally but NOT when deployed to production.
3910
4234
  }, (document) => /* @__PURE__ */ React__default["default"].createElement(RenderForm, {
3911
4235
  cms,
3912
4236
  document,
3913
- filename,
4237
+ filename: resolvedFile,
3914
4238
  relativePath,
3915
4239
  collection,
3916
4240
  mutationInfo
@@ -3928,6 +4252,7 @@ This will work when developing locally but NOT when deployed to production.
3928
4252
  var _a, _b;
3929
4253
  const [formIsPristine, setFormIsPristine] = React.useState(true);
3930
4254
  const schema = cms.api.tina.schema;
4255
+ const parentFolder2 = relativePath.split("/").slice(0, -1).join("/");
3931
4256
  const schemaCollection = schema.getCollection(collection.name);
3932
4257
  const template = schema.getTemplateForData({
3933
4258
  collection: schemaCollection,
@@ -3969,7 +4294,7 @@ This will work when developing locally but NOT when deployed to production.
3969
4294
  }, /* @__PURE__ */ React__default["default"].createElement("span", {
3970
4295
  className: "block text-sm leading-tight uppercase text-gray-400 mb-1"
3971
4296
  }, /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Link, {
3972
- to: `/collections/${collection.name}`,
4297
+ to: `/collections/${collection.name}/~${parentFolder2}`,
3973
4298
  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"
3974
4299
  }, collection.label ? collection.label : collection.name), /* @__PURE__ */ React__default["default"].createElement(HiChevronRight, {
3975
4300
  className: "inline-block -mt-0.5 opacity-50"
@@ -4130,22 +4455,42 @@ This will work when developing locally but NOT when deployed to production.
4130
4455
  path: "graphql",
4131
4456
  element: /* @__PURE__ */ React__default["default"].createElement(PlainLayout, null, /* @__PURE__ */ React__default["default"].createElement(Playground, null))
4132
4457
  }), /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Route, {
4133
- path: "collections/:collectionName/new",
4458
+ path: "collections/new/:collectionName",
4134
4459
  element: /* @__PURE__ */ React__default["default"].createElement(DefaultWrapper, {
4135
4460
  cms
4136
4461
  }, /* @__PURE__ */ React__default["default"].createElement(CollectionCreatePage, null))
4137
4462
  }), /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Route, {
4138
- path: "collections/:collectionName/:templateName/new",
4463
+ path: "collections/duplicate/:collectionName/~/*",
4464
+ element: /* @__PURE__ */ React__default["default"].createElement(DefaultWrapper, {
4465
+ cms
4466
+ }, /* @__PURE__ */ React__default["default"].createElement(CollectionDuplicatePage, null))
4467
+ }), /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Route, {
4468
+ path: "collections/duplicate/:collectionName/*",
4469
+ element: /* @__PURE__ */ React__default["default"].createElement(DefaultWrapper, {
4470
+ cms
4471
+ }, /* @__PURE__ */ React__default["default"].createElement(CollectionDuplicatePage, null))
4472
+ }), /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Route, {
4473
+ path: "collections/new/:collectionName/:templateName",
4139
4474
  element: /* @__PURE__ */ React__default["default"].createElement(DefaultWrapper, {
4140
4475
  cms
4141
4476
  }, /* @__PURE__ */ React__default["default"].createElement(CollectionCreatePage, null))
4142
4477
  }), /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Route, {
4143
- path: "collections/:collectionName/*",
4478
+ path: "collections/new/:collectionName/:templateName/~/*",
4479
+ element: /* @__PURE__ */ React__default["default"].createElement(DefaultWrapper, {
4480
+ cms
4481
+ }, /* @__PURE__ */ React__default["default"].createElement(CollectionCreatePage, null))
4482
+ }), /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Route, {
4483
+ path: "collections/new/:collectionName/~/*",
4484
+ element: /* @__PURE__ */ React__default["default"].createElement(DefaultWrapper, {
4485
+ cms
4486
+ }, /* @__PURE__ */ React__default["default"].createElement(CollectionCreatePage, null))
4487
+ }), /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Route, {
4488
+ path: "collections/edit/:collectionName/*",
4144
4489
  element: /* @__PURE__ */ React__default["default"].createElement(DefaultWrapper, {
4145
4490
  cms
4146
4491
  }, /* @__PURE__ */ React__default["default"].createElement(CollectionUpdatePage, null))
4147
4492
  }), /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Route, {
4148
- path: "collections/:collectionName",
4493
+ path: "collections/:collectionName/*",
4149
4494
  element: /* @__PURE__ */ React__default["default"].createElement(DefaultWrapper, {
4150
4495
  cms
4151
4496
  }, /* @__PURE__ */ React__default["default"].createElement(CollectionListPage, null))