tinacms 0.68.14 → 0.69.1

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.
@@ -25,7 +25,7 @@ export declare class TinaAdminApi {
25
25
  collection: string;
26
26
  relativePath: string;
27
27
  }): Promise<void>;
28
- fetchCollection(collectionName: string, includeDocuments: boolean, after?: string): Promise<Collection>;
28
+ fetchCollection(collectionName: string, includeDocuments: boolean, after?: string, sortKey?: string, order?: 'asc' | 'desc'): Promise<Collection>;
29
29
  fetchDocument(collectionName: string, relativePath: string): Promise<{
30
30
  document: DocumentForm;
31
31
  }>;
@@ -12,17 +12,19 @@ limitations under the License.
12
12
  */
13
13
  import type { TinaCMS } from '@tinacms/toolkit';
14
14
  import type { Collection } from '../types';
15
- export declare const useGetCollection: (cms: TinaCMS, collectionName: string, includeDocuments?: boolean, after?: string) => {
15
+ export declare const useGetCollection: (cms: TinaCMS, collectionName: string, includeDocuments?: boolean, after?: string, sortKey?: string) => {
16
16
  collection: Collection;
17
17
  loading: boolean;
18
18
  error: Error;
19
19
  reFetchCollection: () => void;
20
+ collectionExtra: import("@tinacms/schema-tools").TinaCloudCollection<true>;
20
21
  };
21
- declare const GetCollection: ({ cms, collectionName, includeDocuments, startCursor, children, }: {
22
+ declare const GetCollection: ({ cms, collectionName, includeDocuments, startCursor, sortKey, children, }: {
22
23
  cms: TinaCMS;
23
24
  collectionName: string;
24
25
  includeDocuments?: boolean;
25
26
  startCursor?: string;
27
+ sortKey?: string;
26
28
  children: any;
27
29
  }) => JSX.Element;
28
30
  export default GetCollection;
package/dist/index.d.ts CHANGED
@@ -20,7 +20,8 @@ export * from '@tinacms/toolkit';
20
20
  export { TinaAdmin } from './admin';
21
21
  export { RouteMappingPlugin } from './admin/plugins/route-mapping';
22
22
  export { TinaAdminApi } from './admin/api';
23
- import { TinaCMSProvider2, TinaCMSProviderDefaultProps } from './tina-cms';
23
+ import { TinaCMSProvider2 } from './tina-cms';
24
+ import type { TinaCMSProviderDefaultProps } from './types/cms';
24
25
  export type { TinaCMSProviderDefaultProps };
25
26
  export default TinaCMSProvider2;
26
27
  import type { TinaCloudSchema as TinaCloudSchemaBase, TinaCloudCollection as TinaCloudCollectionBase, TinaCloudTemplateBase as TinaTemplate, TinaFieldBase } from '@tinacms/schema-tools';
package/dist/index.es.js CHANGED
@@ -1,4 +1,4 @@
1
- import { useCMS, Form, GlobalFormPlugin, EventBus, Modal, ModalPopup, ModalHeader, ModalBody, ModalActions, Button, LoadingDots, useLocalStorage, TinaCMS, BranchSwitcherPlugin, BranchDataProvider, TinaProvider, TinaMediaStore, DummyMediaStore, Nav, LocalWarning, OverflowMenu, CursorPaginator, PopupModal, FormStatus, FormBuilder } from "@tinacms/toolkit";
1
+ import { useCMS, Form, GlobalFormPlugin, EventBus, Modal, ModalPopup, ModalHeader, ModalBody, ModalActions, Button, LoadingDots, useLocalStorage, TinaCMS, BranchSwitcherPlugin, BranchDataProvider, TinaProvider, TinaMediaStore, DummyMediaStore, Nav, LocalWarning, Select, OverflowMenu, CursorPaginator, PopupModal, FormStatus, FormBuilder } from "@tinacms/toolkit";
2
2
  export * from "@tinacms/toolkit";
3
3
  import * as G from "graphql";
4
4
  import { TypeInfo, visit, visitWithTypeInfo, getNamedType, GraphQLObjectType, isLeafType, GraphQLUnionType, isScalarType as isScalarType$1, getIntrospectionQuery, buildClientSchema, print, parse } from "graphql";
@@ -1175,7 +1175,8 @@ const formify = async ({
1175
1175
  return formifyInlineFragmentNode({
1176
1176
  inlineFragmentNode: selectionNode,
1177
1177
  parentType: type,
1178
- path
1178
+ path,
1179
+ showInSidebar: true
1179
1180
  });
1180
1181
  }
1181
1182
  case "Field": {
@@ -1245,7 +1246,8 @@ const formify = async ({
1245
1246
  return formifyInlineFragmentNode({
1246
1247
  inlineFragmentNode: selectionNode,
1247
1248
  parentType: field.type,
1248
- path: fieldPath
1249
+ path: fieldPath,
1250
+ showInSidebar: false
1249
1251
  });
1250
1252
  }
1251
1253
  default:
@@ -1259,7 +1261,8 @@ const formify = async ({
1259
1261
  const formifyInlineFragmentNode = ({
1260
1262
  inlineFragmentNode,
1261
1263
  parentType,
1262
- path
1264
+ path,
1265
+ showInSidebar
1263
1266
  }) => {
1264
1267
  const type = getSelectedUnionType(parentType, inlineFragmentNode);
1265
1268
  if (!type) {
@@ -1270,7 +1273,7 @@ const formify = async ({
1270
1273
  inlineFragmentNode,
1271
1274
  type,
1272
1275
  path,
1273
- showInSidebar: false
1276
+ showInSidebar
1274
1277
  });
1275
1278
  }
1276
1279
  return {
@@ -2483,10 +2486,10 @@ class TinaAdminApi {
2483
2486
  }
2484
2487
  }`, { variables: { collection, relativePath } });
2485
2488
  }
2486
- async fetchCollection(collectionName, includeDocuments, after) {
2489
+ async fetchCollection(collectionName, includeDocuments, after, sortKey, order) {
2487
2490
  if (includeDocuments === true) {
2488
- const sort = this.schema.getIsTitleFieldName(collectionName);
2489
- const response = await this.api.request(`#graphql
2491
+ const sort = sortKey || this.schema.getIsTitleFieldName(collectionName);
2492
+ const response = order === "asc" ? await this.api.request(`#graphql
2490
2493
  query($collection: String!, $includeDocuments: Boolean!, $sort: String, $limit: Float, $after: String){
2491
2494
  collection(collection: $collection){
2492
2495
  name
@@ -2527,6 +2530,47 @@ class TinaAdminApi {
2527
2530
  limit: 10,
2528
2531
  after
2529
2532
  }
2533
+ }) : await this.api.request(`#graphql
2534
+ query($collection: String!, $includeDocuments: Boolean!, $sort: String, $limit: Float, $after: String){
2535
+ collection(collection: $collection){
2536
+ name
2537
+ label
2538
+ format
2539
+ templates
2540
+ documents(sort: $sort, before: $after, last: $limit) @include(if: $includeDocuments) {
2541
+ totalCount
2542
+ pageInfo {
2543
+ hasPreviousPage
2544
+ hasNextPage
2545
+ startCursor
2546
+ endCursor
2547
+ }
2548
+ edges {
2549
+ node {
2550
+ ... on Document {
2551
+ _sys {
2552
+ title
2553
+ template
2554
+ breadcrumbs
2555
+ path
2556
+ basename
2557
+ relativePath
2558
+ filename
2559
+ extension
2560
+ }
2561
+ }
2562
+ }
2563
+ }
2564
+ }
2565
+ }
2566
+ }`, {
2567
+ variables: {
2568
+ collection: collectionName,
2569
+ includeDocuments,
2570
+ sort,
2571
+ limit: 10,
2572
+ after
2573
+ }
2530
2574
  });
2531
2575
  return response.collection;
2532
2576
  } else {
@@ -3280,6 +3324,9 @@ var styles = /* @__PURE__ */ (() => `.tina-tailwind {
3280
3324
  .tina-tailwind .gap-4 {
3281
3325
  gap: 16px;
3282
3326
  }
3327
+ .tina-tailwind .gap-2 {
3328
+ gap: 8px;
3329
+ }
3283
3330
  .tina-tailwind .gap-3 {
3284
3331
  gap: 12px;
3285
3332
  }
@@ -3298,6 +3345,9 @@ var styles = /* @__PURE__ */ (() => `.tina-tailwind {
3298
3345
  .tina-tailwind .overflow-y-auto {
3299
3346
  overflow-y: auto;
3300
3347
  }
3348
+ .tina-tailwind .whitespace-normal {
3349
+ white-space: normal;
3350
+ }
3301
3351
  .tina-tailwind .whitespace-nowrap {
3302
3352
  white-space: nowrap;
3303
3353
  }
@@ -3419,8 +3469,8 @@ var styles = /* @__PURE__ */ (() => `.tina-tailwind {
3419
3469
  .tina-tailwind .pb-4 {
3420
3470
  padding-bottom: 16px;
3421
3471
  }
3422
- .tina-tailwind .pt-18 {
3423
- padding-top: 72px;
3472
+ .tina-tailwind .pt-16 {
3473
+ padding-top: 64px;
3424
3474
  }
3425
3475
  .tina-tailwind .pt-3 {
3426
3476
  padding-top: 12px;
@@ -3464,6 +3514,9 @@ var styles = /* @__PURE__ */ (() => `.tina-tailwind {
3464
3514
  .tina-tailwind .font-medium {
3465
3515
  font-weight: 500;
3466
3516
  }
3517
+ .tina-tailwind .font-semibold {
3518
+ font-weight: 600;
3519
+ }
3467
3520
  .tina-tailwind .uppercase {
3468
3521
  text-transform: uppercase;
3469
3522
  }
@@ -3966,16 +4019,18 @@ const TinaCMSProvider2 = ({
3966
4019
  ...props
3967
4020
  }) => {
3968
4021
  var _a;
3969
- const validOldSetup = new Boolean(props == null ? void 0 : props.isLocalClient) || new Boolean(props == null ? void 0 : props.clientId) && new Boolean(props == null ? void 0 : props.branch);
3970
- const apiURL = ((_a = props == null ? void 0 : props.client) == null ? void 0 : _a.apiUrl) || (props == null ? void 0 : props.apiURL);
3971
- if (!apiURL && !validOldSetup) {
3972
- throw new Error(`Must provide apiUrl or a client to the TinaWrapper component`);
4022
+ if (props == null ? void 0 : props.apiURL) {
4023
+ console.warn("The apiURL prop is deprecated. Please see https://tina.io/blog/tina-v-0.68.14 for information on how to upgrade to the new API");
3973
4024
  }
4025
+ const apiURL = ((_a = props == null ? void 0 : props.client) == null ? void 0 : _a.apiUrl) || (props == null ? void 0 : props.apiURL);
3974
4026
  const { branch, clientId, isLocalClient } = apiURL ? parseURL(apiURL) : {
3975
4027
  branch: props.branch,
3976
4028
  clientId: props.clientId,
3977
- isLocalClient: props.isLocalClient
4029
+ isLocalClient: props == null ? void 0 : props.isLocalClient
3978
4030
  };
4031
+ if (typeof isLocalClient === "undefined" || !isLocalClient && (!branch || !clientId)) {
4032
+ throw new Error("Invalid setup. See https://tina.io/docs/tina-cloud/connecting-site/ for more information.");
4033
+ }
3979
4034
  if (!schema) {
3980
4035
  throw new Error("`schema` is required to be passed as a property to `TinaProvider`. You can learn more about this change here: https://github.com/tinacms/tinacms/pull/2823");
3981
4036
  }
@@ -4558,7 +4613,7 @@ const PageHeader = ({
4558
4613
  isLocalMode,
4559
4614
  children
4560
4615
  }) => /* @__PURE__ */ React.createElement(React.Fragment, null, isLocalMode && /* @__PURE__ */ React.createElement(LocalWarning, null), /* @__PURE__ */ React.createElement("div", {
4561
- className: "bg-white pb-4 pt-18 border-b border-gray-200 px-12"
4616
+ className: "bg-white pb-4 pt-16 border-b border-gray-200 px-12"
4562
4617
  }, /* @__PURE__ */ React.createElement("div", {
4563
4618
  className: "w-full mx-auto max-w-screen-xl"
4564
4619
  }, /* @__PURE__ */ React.createElement("div", {
@@ -4685,8 +4740,10 @@ const LoadingPage = () => /* @__PURE__ */ React.createElement(React.Fragment, nu
4685
4740
  fontWeight: "normal"
4686
4741
  }
4687
4742
  }, "Please wait, Tina is loading data..."))));
4688
- const useGetCollection = (cms, collectionName, includeDocuments = true, after = "") => {
4743
+ const useGetCollection = (cms, collectionName, includeDocuments = true, after = "", sortKey) => {
4689
4744
  const api = new TinaAdminApi(cms);
4745
+ const schema = cms.api.tina.schema;
4746
+ const collectionExtra = schema.getCollection(collectionName);
4690
4747
  const [collection, setCollection] = useState(void 0);
4691
4748
  const [loading, setLoading] = useState(true);
4692
4749
  const [error, setError] = useState(void 0);
@@ -4694,8 +4751,10 @@ const useGetCollection = (cms, collectionName, includeDocuments = true, after =
4694
4751
  useEffect(() => {
4695
4752
  const fetchCollection = async () => {
4696
4753
  if (await api.isAuthenticated()) {
4754
+ const { name, order } = JSON.parse(sortKey || "{}");
4755
+ const validSortKey = collectionExtra.fields.map((x) => x.name).includes(name) ? name : void 0;
4697
4756
  try {
4698
- const collection2 = await api.fetchCollection(collectionName, includeDocuments, after);
4757
+ const collection2 = await api.fetchCollection(collectionName, includeDocuments, after, validSortKey, order);
4699
4758
  setCollection(collection2);
4700
4759
  } catch (error2) {
4701
4760
  cms.alerts.error(`[${error2.name}] GetCollection failed: ${error2.message}`, 30 * 1e3);
@@ -4708,26 +4767,29 @@ const useGetCollection = (cms, collectionName, includeDocuments = true, after =
4708
4767
  };
4709
4768
  setLoading(true);
4710
4769
  fetchCollection();
4711
- }, [cms, collectionName, resetState, after]);
4770
+ }, [cms, collectionName, resetState, after, sortKey]);
4712
4771
  const reFetchCollection = () => setResetSate((x) => x + 1);
4713
- return { collection, loading, error, reFetchCollection };
4772
+ return { collection, loading, error, reFetchCollection, collectionExtra };
4714
4773
  };
4715
4774
  const GetCollection = ({
4716
4775
  cms,
4717
4776
  collectionName,
4718
4777
  includeDocuments = true,
4719
4778
  startCursor,
4779
+ sortKey,
4720
4780
  children
4721
4781
  }) => {
4722
- const { collection, loading, error, reFetchCollection } = useGetCollection(cms, collectionName, includeDocuments, startCursor || "");
4782
+ const { collection, loading, error, reFetchCollection, collectionExtra } = useGetCollection(cms, collectionName, includeDocuments, startCursor || "", sortKey) || {};
4723
4783
  if (error) {
4724
4784
  return null;
4725
4785
  }
4726
4786
  if (loading) {
4727
4787
  return /* @__PURE__ */ React.createElement(LoadingPage, null);
4728
4788
  }
4729
- return /* @__PURE__ */ React.createElement(React.Fragment, null, children(collection, loading, reFetchCollection));
4789
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, children(collection, loading, reFetchCollection, collectionExtra));
4730
4790
  };
4791
+ const LOCAL_STORAGE_KEY = "tinacms.admin.collection.list.page";
4792
+ const isSSR = typeof window === "undefined";
4731
4793
  const TemplateMenu = ({ templates }) => {
4732
4794
  return /* @__PURE__ */ React.createElement(Menu, {
4733
4795
  as: "div",
@@ -4776,8 +4838,17 @@ const CollectionListPage = () => {
4776
4838
  });
4777
4839
  const [endCursor, setEndCursor] = useState("");
4778
4840
  const [prevCursors, setPrevCursors] = useState([]);
4841
+ const [sortKey, setSortKey] = useState(isSSR ? "" : window.localStorage.getItem(`${LOCAL_STORAGE_KEY}.${collectionName}`) || JSON.stringify({
4842
+ order: "asc",
4843
+ name: ""
4844
+ }));
4845
+ const [sortOrder, setSortOrder] = useState("asc");
4779
4846
  const loc = useLocation();
4780
4847
  useEffect(() => {
4848
+ setSortKey(window.localStorage.getItem(`${LOCAL_STORAGE_KEY}.${collectionName}`) || JSON.stringify({
4849
+ order: "asc",
4850
+ name: ""
4851
+ }));
4781
4852
  setEndCursor("");
4782
4853
  setPrevCursors([]);
4783
4854
  }, [loc]);
@@ -4786,13 +4857,15 @@ const CollectionListPage = () => {
4786
4857
  cms,
4787
4858
  collectionName,
4788
4859
  includeDocuments: true,
4789
- startCursor: endCursor
4790
- }, (collection, _loading, reFetchCollection) => {
4860
+ startCursor: endCursor,
4861
+ sortKey
4862
+ }, (collection, _loading, reFetchCollection, collectionExtra) => {
4791
4863
  var _a, _b;
4792
4864
  const totalCount = collection.documents.totalCount;
4793
4865
  const documents = collection.documents.edges;
4794
4866
  const admin = cms.api.admin;
4795
4867
  const pageInfo = collection.documents.pageInfo;
4868
+ const fields = collectionExtra.fields.filter((x) => ["string", "number", "datetime"].includes(x.type));
4796
4869
  return /* @__PURE__ */ React.createElement(PageWrapper, null, /* @__PURE__ */ React.createElement(React.Fragment, null, open && /* @__PURE__ */ React.createElement(DeleteModal, {
4797
4870
  filename: vars.relativePath,
4798
4871
  deleteFunc: async () => {
@@ -4809,9 +4882,56 @@ const CollectionListPage = () => {
4809
4882
  close: () => setOpen(false)
4810
4883
  }), /* @__PURE__ */ React.createElement(PageHeader, {
4811
4884
  isLocalMode: (_b = (_a = cms == null ? void 0 : cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.isLocalMode
4812
- }, /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("h3", {
4885
+ }, /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", {
4886
+ className: "flex flex-col gap-4"
4887
+ }, /* @__PURE__ */ React.createElement("h3", {
4813
4888
  className: "font-sans text-2xl text-gray-700"
4814
- }, collection.label ? collection.label : collection.name), !collection.templates && /* @__PURE__ */ React.createElement(Link, {
4889
+ }, collection.label ? collection.label : collection.name), fields.length > 0 && /* @__PURE__ */ React.createElement("div", {
4890
+ className: "flex gap-2 items-center"
4891
+ }, /* @__PURE__ */ React.createElement("label", {
4892
+ htmlFor: "sort",
4893
+ className: "block font-sans text-xs font-semibold text-gray-500 whitespace-normal"
4894
+ }, "Sort by"), /* @__PURE__ */ React.createElement(Select, {
4895
+ name: "sort",
4896
+ options: [
4897
+ {
4898
+ label: "Default",
4899
+ value: JSON.stringify({
4900
+ order: "asc",
4901
+ name: ""
4902
+ })
4903
+ },
4904
+ ...fields.map((x) => [
4905
+ {
4906
+ label: x.label + " (Ascending)",
4907
+ value: JSON.stringify({
4908
+ name: x.name,
4909
+ order: "asc"
4910
+ })
4911
+ },
4912
+ {
4913
+ label: x.label + " (Descending)",
4914
+ value: JSON.stringify({
4915
+ name: x.name,
4916
+ order: "desc"
4917
+ })
4918
+ }
4919
+ ]).flat()
4920
+ ],
4921
+ input: {
4922
+ id: "sort",
4923
+ name: "sort",
4924
+ value: sortKey,
4925
+ onChange: (e) => {
4926
+ const val = JSON.parse(e.target.value);
4927
+ setEndCursor("");
4928
+ setPrevCursors([]);
4929
+ window == null ? void 0 : window.localStorage.setItem(`${LOCAL_STORAGE_KEY}.${collectionName}`, e.target.value);
4930
+ setSortKey(e.target.value);
4931
+ setSortOrder(val.order);
4932
+ }
4933
+ }
4934
+ }))), !collection.templates && /* @__PURE__ */ React.createElement(Link, {
4815
4935
  to: `new`,
4816
4936
  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 shadow text-white bg-blue-500 hover:bg-blue-600 focus:ring-blue-500 text-sm h-10 px-6"
4817
4937
  }, "Create New", " ", /* @__PURE__ */ React.createElement(BiPlus, {
@@ -4899,7 +5019,7 @@ const CollectionListPage = () => {
4899
5019
  className: "pt-3"
4900
5020
  }, /* @__PURE__ */ React.createElement(CursorPaginator, {
4901
5021
  variant: "white",
4902
- hasNext: pageInfo == null ? void 0 : pageInfo.hasNextPage,
5022
+ hasNext: sortOrder === "asc" ? pageInfo == null ? void 0 : pageInfo.hasNextPage : pageInfo.hasPreviousPage,
4903
5023
  navigateNext: () => {
4904
5024
  const newState = [...prevCursors, endCursor];
4905
5025
  setPrevCursors(newState);
@@ -5237,9 +5357,9 @@ const Redirect = () => {
5237
5357
  return null;
5238
5358
  };
5239
5359
  const TinaAdmin = () => {
5240
- const isSSR = typeof window === "undefined";
5360
+ const isSSR2 = typeof window === "undefined";
5241
5361
  const { edit } = useEditState();
5242
- if (isSSR) {
5362
+ if (isSSR2) {
5243
5363
  return null;
5244
5364
  }
5245
5365
  if (!edit) {