tinacms 1.5.7 → 1.5.9
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/admin/api.d.ts +10 -7
- package/dist/admin/components/GetCollection.d.ts +15 -3
- package/dist/admin/types.d.ts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.es.js +472 -208
- package/dist/index.js +472 -206
- package/dist/internalClient/index.d.ts +34 -1
- package/dist/style.css +3 -0
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -54,6 +54,152 @@
|
|
|
54
54
|
authTab = popupWindow(`${frontendUrl}/signin?clientId=${clientId}&origin=${origin}`, "_blank", window, 1e3, 700);
|
|
55
55
|
});
|
|
56
56
|
};
|
|
57
|
+
class StringBuilder {
|
|
58
|
+
constructor(limit) {
|
|
59
|
+
this.length = 0;
|
|
60
|
+
this.buffer = [];
|
|
61
|
+
this.limit = limit;
|
|
62
|
+
}
|
|
63
|
+
append(str) {
|
|
64
|
+
if (this.length + str.length > this.limit) {
|
|
65
|
+
return true;
|
|
66
|
+
} else {
|
|
67
|
+
this.buffer.push(str);
|
|
68
|
+
this.length += str.length;
|
|
69
|
+
if (this.length > this.limit) {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
toString() {
|
|
76
|
+
return this.buffer.join(" ");
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const extractText = (data, acc, indexableNodeTypes) => {
|
|
80
|
+
var _a, _b;
|
|
81
|
+
if (data) {
|
|
82
|
+
if (indexableNodeTypes.indexOf(data.type) !== -1 && (data.text || data.value)) {
|
|
83
|
+
const tokens = tokenizeString(data.text || data.value);
|
|
84
|
+
for (const token of tokens) {
|
|
85
|
+
if (acc.append(token)) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
(_b = (_a = data.children) == null ? void 0 : _a.forEach) == null ? void 0 : _b.call(_a, (child) => extractText(child, acc, indexableNodeTypes));
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
const relativePath = (path, collection) => {
|
|
94
|
+
return path.replace(/\\/g, "/").replace(collection.path, "").replace(/^\/|\/$/g, "");
|
|
95
|
+
};
|
|
96
|
+
const tokenizeString = (str) => {
|
|
97
|
+
return str.split(/[\s\.,]+/).map((s) => s.toLowerCase()).filter((s) => s);
|
|
98
|
+
};
|
|
99
|
+
const processTextFieldValue = (value, maxLen) => {
|
|
100
|
+
const tokens = tokenizeString(value);
|
|
101
|
+
const builder = new StringBuilder(maxLen);
|
|
102
|
+
for (const part of tokens) {
|
|
103
|
+
if (builder.append(part)) {
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return builder.toString();
|
|
108
|
+
};
|
|
109
|
+
const processDocumentForIndexing = (data, path, collection, textIndexLength, field) => {
|
|
110
|
+
if (!field) {
|
|
111
|
+
const relPath = relativePath(path, collection);
|
|
112
|
+
data["_id"] = `${collection.name}:${relPath}`;
|
|
113
|
+
data["_relativePath"] = relPath;
|
|
114
|
+
}
|
|
115
|
+
for (const f of collection.fields || (field == null ? void 0 : field.fields) || []) {
|
|
116
|
+
if (!f.searchable) {
|
|
117
|
+
delete data[f.name];
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
const isList = f.list;
|
|
121
|
+
if (data[f.name]) {
|
|
122
|
+
if (f.type === "object") {
|
|
123
|
+
if (isList) {
|
|
124
|
+
data[f.name] = data[f.name].map((obj) => processDocumentForIndexing(obj, path, collection, textIndexLength, f));
|
|
125
|
+
} else {
|
|
126
|
+
data[f.name] = processDocumentForIndexing(data[f.name], path, collection, textIndexLength, f);
|
|
127
|
+
}
|
|
128
|
+
} else if (f.type === "string") {
|
|
129
|
+
const fieldTextIndexLength = f.maxSearchIndexFieldLength || textIndexLength;
|
|
130
|
+
if (isList) {
|
|
131
|
+
data[f.name] = data[f.name].map((value) => processTextFieldValue(value, fieldTextIndexLength));
|
|
132
|
+
} else {
|
|
133
|
+
data[f.name] = processTextFieldValue(data[f.name], fieldTextIndexLength);
|
|
134
|
+
}
|
|
135
|
+
} else if (f.type === "rich-text") {
|
|
136
|
+
const fieldTextIndexLength = f.maxSearchIndexFieldLength || textIndexLength;
|
|
137
|
+
if (isList) {
|
|
138
|
+
data[f.name] = data[f.name].map((value) => {
|
|
139
|
+
const acc = new StringBuilder(fieldTextIndexLength);
|
|
140
|
+
extractText(value, acc, ["text", "code_block", "html"]);
|
|
141
|
+
return acc.toString();
|
|
142
|
+
});
|
|
143
|
+
} else {
|
|
144
|
+
const acc = new StringBuilder(fieldTextIndexLength);
|
|
145
|
+
extractText(data[f.name], acc, ["text", "code_block", "html"]);
|
|
146
|
+
data[f.name] = acc.toString();
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return data;
|
|
152
|
+
};
|
|
153
|
+
const queryToSearchIndexQuery = (query) => {
|
|
154
|
+
let q;
|
|
155
|
+
const parts = query.split(" ");
|
|
156
|
+
if (parts.length === 1) {
|
|
157
|
+
q = { AND: [parts[0]] };
|
|
158
|
+
} else {
|
|
159
|
+
q = { AND: parts.filter((part) => part.toLowerCase() !== "and") };
|
|
160
|
+
}
|
|
161
|
+
return q;
|
|
162
|
+
};
|
|
163
|
+
const optionsToSearchIndexOptions = (options) => {
|
|
164
|
+
const opt = {};
|
|
165
|
+
if (options == null ? void 0 : options.limit) {
|
|
166
|
+
opt["PAGE"] = {
|
|
167
|
+
SIZE: options.limit,
|
|
168
|
+
NUMBER: (options == null ? void 0 : options.cursor) ? parseInt(options.cursor) : 0
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
return opt;
|
|
172
|
+
};
|
|
173
|
+
const parseSearchIndexResponse = (data, options) => {
|
|
174
|
+
const results = data["RESULT"];
|
|
175
|
+
const total = data["RESULT_LENGTH"];
|
|
176
|
+
if ((options == null ? void 0 : options.cursor) && (options == null ? void 0 : options.limit)) {
|
|
177
|
+
const prevCursor = options.cursor === "0" ? null : (parseInt(options.cursor) - 1).toString();
|
|
178
|
+
const nextCursor = total <= (parseInt(options.cursor) + 1) * options.limit ? null : (parseInt(options.cursor) + 1).toString();
|
|
179
|
+
return {
|
|
180
|
+
results,
|
|
181
|
+
total,
|
|
182
|
+
prevCursor,
|
|
183
|
+
nextCursor
|
|
184
|
+
};
|
|
185
|
+
} else if (!(options == null ? void 0 : options.cursor) && (options == null ? void 0 : options.limit)) {
|
|
186
|
+
const prevCursor = null;
|
|
187
|
+
const nextCursor = total <= options.limit ? null : "1";
|
|
188
|
+
return {
|
|
189
|
+
results,
|
|
190
|
+
total,
|
|
191
|
+
prevCursor,
|
|
192
|
+
nextCursor
|
|
193
|
+
};
|
|
194
|
+
} else {
|
|
195
|
+
return {
|
|
196
|
+
results,
|
|
197
|
+
total,
|
|
198
|
+
prevCursor: null,
|
|
199
|
+
nextCursor: null
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
};
|
|
57
203
|
const captureBranchName = /^refs\/heads\/(.*)/;
|
|
58
204
|
const parseRefForBranchName = (ref) => {
|
|
59
205
|
const matches = ref.match(captureBranchName);
|
|
@@ -232,6 +378,9 @@ mutation addPendingDocumentMutation(
|
|
|
232
378
|
this.contentApiBase = ((_d = this.options.tinaioConfig) == null ? void 0 : _d.contentApiUrlOverride) || `https://content.tinajs.io`;
|
|
233
379
|
this.contentApiUrl = this.options.customContentApiUrl || `${this.contentApiBase}/${this.tinaGraphQLVersion}/content/${this.options.clientId}/github/${encodedBranch}`;
|
|
234
380
|
}
|
|
381
|
+
getBranch() {
|
|
382
|
+
return this.branch;
|
|
383
|
+
}
|
|
235
384
|
async request(query, { variables }) {
|
|
236
385
|
const token = await this.getToken();
|
|
237
386
|
const headers = {
|
|
@@ -517,6 +666,62 @@ mutation addPendingDocumentMutation(
|
|
|
517
666
|
return localStorage.getItem(LOCAL_CLIENT_KEY) === "true";
|
|
518
667
|
}
|
|
519
668
|
}
|
|
669
|
+
class TinaCMSSearchClient {
|
|
670
|
+
constructor(client) {
|
|
671
|
+
this.client = client;
|
|
672
|
+
}
|
|
673
|
+
async query(query, options) {
|
|
674
|
+
const q = queryToSearchIndexQuery(query);
|
|
675
|
+
const opt = optionsToSearchIndexOptions(options);
|
|
676
|
+
const optionsParam = opt["PAGE"] ? `&options=${JSON.stringify(opt)}` : "";
|
|
677
|
+
const res = await this.client.fetchWithToken(`${this.client.contentApiBase}/searchIndex/${this.client.clientId}/${this.client.getBranch()}?q=${JSON.stringify(q)}${optionsParam}`);
|
|
678
|
+
return parseSearchIndexResponse(await res.json(), options);
|
|
679
|
+
}
|
|
680
|
+
async del(ids) {
|
|
681
|
+
const res = await this.client.fetchWithToken(`${this.client.contentApiBase}/searchIndex/${this.client.clientId}/${this.client.getBranch()}?ids=${ids.join(",")}`, {
|
|
682
|
+
method: "DELETE"
|
|
683
|
+
});
|
|
684
|
+
if (res.status !== 200) {
|
|
685
|
+
throw new Error("Failed to update search index");
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
async put(docs) {
|
|
689
|
+
const res = await this.client.fetchWithToken(`${this.client.contentApiBase}/searchIndex/${this.client.clientId}/${this.client.getBranch()}`, {
|
|
690
|
+
method: "POST",
|
|
691
|
+
body: JSON.stringify({ docs }),
|
|
692
|
+
headers: {
|
|
693
|
+
"Content-Type": "application/json"
|
|
694
|
+
}
|
|
695
|
+
});
|
|
696
|
+
if (res.status !== 200) {
|
|
697
|
+
throw new Error("Failed to update search index");
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
supportsClientSideIndexing() {
|
|
701
|
+
return true;
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
class LocalSearchClient {
|
|
705
|
+
constructor(client) {
|
|
706
|
+
this.client = client;
|
|
707
|
+
}
|
|
708
|
+
async query(query, options) {
|
|
709
|
+
const q = queryToSearchIndexQuery(query);
|
|
710
|
+
const opt = optionsToSearchIndexOptions(options);
|
|
711
|
+
const optionsParam = opt["PAGE"] ? `&options=${JSON.stringify(opt)}` : "";
|
|
712
|
+
const res = await this.client.fetchWithToken(`http://localhost:4001/searchIndex?q=${JSON.stringify(q)}${optionsParam}`);
|
|
713
|
+
return parseSearchIndexResponse(await res.json(), options);
|
|
714
|
+
}
|
|
715
|
+
del(ids) {
|
|
716
|
+
return Promise.resolve(void 0);
|
|
717
|
+
}
|
|
718
|
+
put(docs) {
|
|
719
|
+
return Promise.resolve(void 0);
|
|
720
|
+
}
|
|
721
|
+
supportsClientSideIndexing() {
|
|
722
|
+
return false;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
520
725
|
function ModalBuilder(modalProps) {
|
|
521
726
|
return /* @__PURE__ */ React__default["default"].createElement(toolkit.Modal, null, /* @__PURE__ */ React__default["default"].createElement(toolkit.ModalPopup, null, /* @__PURE__ */ React__default["default"].createElement(toolkit.ModalHeader, null, modalProps.title), /* @__PURE__ */ React__default["default"].createElement(toolkit.ModalBody, {
|
|
522
727
|
padded: true
|
|
@@ -601,8 +806,14 @@ mutation addPendingDocumentMutation(
|
|
|
601
806
|
}
|
|
602
807
|
class TinaAdminApi {
|
|
603
808
|
constructor(cms) {
|
|
809
|
+
var _a, _b, _c, _d;
|
|
810
|
+
this.maxSearchIndexFieldLength = 100;
|
|
604
811
|
this.api = cms.api.tina;
|
|
605
812
|
this.schema = cms.api.tina.schema;
|
|
813
|
+
if (cms.api.search && ((_a = cms.api.search) == null ? void 0 : _a.supportsClientSideIndexing())) {
|
|
814
|
+
this.searchClient = cms.api.searchClient;
|
|
815
|
+
this.maxSearchIndexFieldLength = ((_d = (_c = (_b = this.schema.config) == null ? void 0 : _b.config) == null ? void 0 : _c.search) == null ? void 0 : _d.maxSearchIndexFieldLength) || 100;
|
|
816
|
+
}
|
|
606
817
|
}
|
|
607
818
|
async isAuthenticated() {
|
|
608
819
|
return await this.api.isAuthenticated();
|
|
@@ -621,25 +832,33 @@ mutation addPendingDocumentMutation(
|
|
|
621
832
|
fetchCollections() {
|
|
622
833
|
return this.schema.getCollections();
|
|
623
834
|
}
|
|
624
|
-
async renameDocument({ collection, relativePath, newRelativePath }) {
|
|
835
|
+
async renameDocument({ collection, relativePath: relativePath2, newRelativePath }) {
|
|
625
836
|
await this.api.request(`#graphql
|
|
626
837
|
mutation RenameDocument($collection: String!, $relativePath: String! $newRelativePath: String!) {
|
|
627
838
|
updateDocument(collection: $collection, relativePath: $relativePath, params: {relativePath: $newRelativePath}){
|
|
628
839
|
__typename
|
|
629
840
|
}
|
|
630
841
|
}
|
|
631
|
-
`, { variables: { collection, relativePath, newRelativePath } });
|
|
842
|
+
`, { variables: { collection, relativePath: relativePath2, newRelativePath } });
|
|
843
|
+
if (this.searchClient) {
|
|
844
|
+
const { document: doc } = await this.fetchDocument(collection.name, newRelativePath);
|
|
845
|
+
const processed = processDocumentForIndexing(doc["_values"], `${collection.path}/${newRelativePath}`, collection, this.maxSearchIndexFieldLength);
|
|
846
|
+
await this.searchClient.put([processed]);
|
|
847
|
+
await this.searchClient.del([`${collection.name}:${relativePath2}`]);
|
|
848
|
+
}
|
|
632
849
|
}
|
|
633
850
|
async deleteDocument({
|
|
634
851
|
collection,
|
|
635
|
-
relativePath
|
|
852
|
+
relativePath: relativePath2
|
|
636
853
|
}) {
|
|
854
|
+
var _a;
|
|
637
855
|
await this.api.request(`#graphql
|
|
638
856
|
mutation DeleteDocument($collection: String!, $relativePath: String! ){
|
|
639
857
|
deleteDocument(collection: $collection, relativePath: $relativePath){
|
|
640
858
|
__typename
|
|
641
859
|
}
|
|
642
|
-
}`, { variables: { collection, relativePath } });
|
|
860
|
+
}`, { variables: { collection, relativePath: relativePath2 } });
|
|
861
|
+
await ((_a = this.searchClient) == null ? void 0 : _a.del([`${collection}:${relativePath2}`]));
|
|
643
862
|
}
|
|
644
863
|
async fetchCollection(collectionName, includeDocuments, folder = "", after, sortKey, order, filterArgs) {
|
|
645
864
|
let filter = null;
|
|
@@ -785,18 +1004,43 @@ mutation addPendingDocumentMutation(
|
|
|
785
1004
|
}
|
|
786
1005
|
}
|
|
787
1006
|
}
|
|
788
|
-
async fetchDocument(collectionName,
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
1007
|
+
async fetchDocument(collectionName, relativePath2, values = true) {
|
|
1008
|
+
let query;
|
|
1009
|
+
if (values) {
|
|
1010
|
+
query = `#graphql
|
|
1011
|
+
query($collection: String!, $relativePath: String!) {
|
|
1012
|
+
document(collection:$collection, relativePath:$relativePath) {
|
|
1013
|
+
... on Document {
|
|
1014
|
+
_values
|
|
1015
|
+
}
|
|
794
1016
|
}
|
|
795
|
-
}
|
|
796
|
-
}
|
|
1017
|
+
}`;
|
|
1018
|
+
} else {
|
|
1019
|
+
query = `#graphql
|
|
1020
|
+
query($collection: String!, $relativePath: String!) {
|
|
1021
|
+
document(collection:$collection, relativePath:$relativePath) {
|
|
1022
|
+
__typename
|
|
1023
|
+
... on Document {
|
|
1024
|
+
_sys {
|
|
1025
|
+
title
|
|
1026
|
+
template
|
|
1027
|
+
breadcrumbs
|
|
1028
|
+
path
|
|
1029
|
+
basename
|
|
1030
|
+
relativePath
|
|
1031
|
+
filename
|
|
1032
|
+
extension
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
}`;
|
|
1037
|
+
}
|
|
1038
|
+
const response = await this.api.request(query, {
|
|
1039
|
+
variables: { collection: collectionName, relativePath: relativePath2 }
|
|
1040
|
+
});
|
|
797
1041
|
return response;
|
|
798
1042
|
}
|
|
799
|
-
async createDocument(
|
|
1043
|
+
async createDocument(collection, relativePath2, params) {
|
|
800
1044
|
const response = await this.api.request(`#graphql
|
|
801
1045
|
mutation($collection: String!, $relativePath: String!, $params: DocumentMutation!) {
|
|
802
1046
|
createDocument(
|
|
@@ -806,14 +1050,19 @@ mutation addPendingDocumentMutation(
|
|
|
806
1050
|
){__typename}
|
|
807
1051
|
}`, {
|
|
808
1052
|
variables: {
|
|
809
|
-
collection:
|
|
810
|
-
relativePath,
|
|
1053
|
+
collection: collection.name,
|
|
1054
|
+
relativePath: relativePath2,
|
|
811
1055
|
params
|
|
812
1056
|
}
|
|
813
1057
|
});
|
|
1058
|
+
if (this.searchClient) {
|
|
1059
|
+
const { document: doc } = await this.fetchDocument(collection.name, relativePath2);
|
|
1060
|
+
const processed = processDocumentForIndexing(doc["_values"], `${collection.path}/${relativePath2}`, collection, this.maxSearchIndexFieldLength);
|
|
1061
|
+
await this.searchClient.put([processed]);
|
|
1062
|
+
}
|
|
814
1063
|
return response;
|
|
815
1064
|
}
|
|
816
|
-
async updateDocument(
|
|
1065
|
+
async updateDocument(collection, relativePath2, params) {
|
|
817
1066
|
const response = await this.api.request(`#graphql
|
|
818
1067
|
mutation($collection: String!, $relativePath: String!, $params: DocumentUpdateMutation!) {
|
|
819
1068
|
updateDocument(
|
|
@@ -823,11 +1072,16 @@ mutation addPendingDocumentMutation(
|
|
|
823
1072
|
){__typename}
|
|
824
1073
|
}`, {
|
|
825
1074
|
variables: {
|
|
826
|
-
collection:
|
|
827
|
-
relativePath,
|
|
1075
|
+
collection: collection.name,
|
|
1076
|
+
relativePath: relativePath2,
|
|
828
1077
|
params
|
|
829
1078
|
}
|
|
830
1079
|
});
|
|
1080
|
+
if (this.searchClient) {
|
|
1081
|
+
const { document: doc } = await this.fetchDocument(collection.name, relativePath2);
|
|
1082
|
+
const processed = processDocumentForIndexing(doc["_values"], `${collection.path}/${relativePath2}`, collection, this.maxSearchIndexFieldLength);
|
|
1083
|
+
await this.searchClient.put([processed]);
|
|
1084
|
+
}
|
|
831
1085
|
return response;
|
|
832
1086
|
}
|
|
833
1087
|
}
|
|
@@ -913,6 +1167,23 @@ mutation addPendingDocumentMutation(
|
|
|
913
1167
|
} else {
|
|
914
1168
|
cms.api.tina.setBranch(currentBranch);
|
|
915
1169
|
}
|
|
1170
|
+
React.useEffect(() => {
|
|
1171
|
+
var _a, _b, _c, _d;
|
|
1172
|
+
let searchClient;
|
|
1173
|
+
if (props.isLocalClient) {
|
|
1174
|
+
searchClient = new LocalSearchClient(cms.api.tina);
|
|
1175
|
+
} else {
|
|
1176
|
+
const hasTinaSearch = Boolean((_b = (_a = props.schema.config) == null ? void 0 : _a.search) == null ? void 0 : _b.tina);
|
|
1177
|
+
if (hasTinaSearch) {
|
|
1178
|
+
searchClient = new TinaCMSSearchClient(cms.api.tina);
|
|
1179
|
+
} else {
|
|
1180
|
+
searchClient = (_d = (_c = props.schema.config) == null ? void 0 : _c.search) == null ? void 0 : _d.searchClient;
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
if (searchClient) {
|
|
1184
|
+
cms.registerApi("search", searchClient);
|
|
1185
|
+
}
|
|
1186
|
+
}, [props]);
|
|
916
1187
|
if (!cms.api.admin) {
|
|
917
1188
|
cms.registerApi("admin", new TinaAdminApi(cms));
|
|
918
1189
|
}
|
|
@@ -1479,6 +1750,9 @@ mutation addPendingDocumentMutation(
|
|
|
1479
1750
|
.tina-tailwind .w-full {
|
|
1480
1751
|
width: 100%;
|
|
1481
1752
|
}
|
|
1753
|
+
.tina-tailwind .min-w-\\[200px\\] {
|
|
1754
|
+
min-width: 200px;
|
|
1755
|
+
}
|
|
1482
1756
|
.tina-tailwind .max-w-0 {
|
|
1483
1757
|
max-width: 0rem;
|
|
1484
1758
|
}
|
|
@@ -2146,16 +2420,16 @@ mutation addPendingDocumentMutation(
|
|
|
2146
2420
|
this.onChange = options.onChange;
|
|
2147
2421
|
this.initialValues = options.initialValues;
|
|
2148
2422
|
}
|
|
2149
|
-
async onSubmit({ collection, template, relativePath }, cms) {
|
|
2423
|
+
async onSubmit({ collection, template, relativePath: relativePath2 }, cms) {
|
|
2150
2424
|
try {
|
|
2151
2425
|
const selectedCollection = this.collections.find((collectionItem) => collectionItem.slug === collection);
|
|
2152
2426
|
const collectionFormat = selectedCollection.format;
|
|
2153
2427
|
const extensionLength = -1 * (collectionFormat.length + 1);
|
|
2154
|
-
let relativePathWithExt =
|
|
2155
|
-
if (
|
|
2156
|
-
relativePathWithExt = `${
|
|
2428
|
+
let relativePathWithExt = relativePath2;
|
|
2429
|
+
if (relativePath2.slice(extensionLength).toLocaleLowerCase() === `.${collectionFormat}`) {
|
|
2430
|
+
relativePathWithExt = `${relativePath2.slice(0, -3)}.${collectionFormat}`;
|
|
2157
2431
|
} else {
|
|
2158
|
-
relativePathWithExt = `${
|
|
2432
|
+
relativePathWithExt = `${relativePath2}.${collectionFormat}`;
|
|
2159
2433
|
}
|
|
2160
2434
|
const payload = {
|
|
2161
2435
|
relativePath: relativePathWithExt,
|
|
@@ -3173,6 +3447,75 @@ This will work when developing locally but NOT when deployed to production.
|
|
|
3173
3447
|
const reFetchCollection = () => setResetSate((x) => x + 1);
|
|
3174
3448
|
return { collection, loading, error, reFetchCollection, collectionExtra };
|
|
3175
3449
|
};
|
|
3450
|
+
const useSearchCollection = (cms, collectionName, includeDocuments = true, folder, after = "", search) => {
|
|
3451
|
+
const api = new TinaAdminApi(cms);
|
|
3452
|
+
const schema = cms.api.tina.schema;
|
|
3453
|
+
const collectionExtra = schema.getCollection(collectionName);
|
|
3454
|
+
const [collection, setCollection] = React.useState(void 0);
|
|
3455
|
+
const [loading, setLoading] = React.useState(true);
|
|
3456
|
+
const [error, setError] = React.useState(void 0);
|
|
3457
|
+
const [resetState, setResetSate] = React.useState(0);
|
|
3458
|
+
React.useEffect(() => {
|
|
3459
|
+
let cancelled = false;
|
|
3460
|
+
const searchCollection = async () => {
|
|
3461
|
+
if (await api.isAuthenticated() && !folder.loading && !cancelled) {
|
|
3462
|
+
try {
|
|
3463
|
+
const response = await cms.api.search.query(`${search} AND _collection:${collectionName}`, {
|
|
3464
|
+
limit: 15,
|
|
3465
|
+
cursor: after
|
|
3466
|
+
});
|
|
3467
|
+
const docs = await Promise.allSettled(response.results.map((result) => {
|
|
3468
|
+
const [collection2, relativePath2] = result._id.split(":");
|
|
3469
|
+
return api.fetchDocument(collection2, relativePath2, false);
|
|
3470
|
+
}));
|
|
3471
|
+
const edges = docs.filter((p) => {
|
|
3472
|
+
var _a;
|
|
3473
|
+
return p.status === "fulfilled" && !!((_a = p.value) == null ? void 0 : _a.document);
|
|
3474
|
+
}).map((result) => ({ node: result.value.document }));
|
|
3475
|
+
const c = await api.fetchCollection(collectionName, false, "");
|
|
3476
|
+
setCollection({
|
|
3477
|
+
format: collection.format,
|
|
3478
|
+
label: collection.label,
|
|
3479
|
+
name: collectionName,
|
|
3480
|
+
templates: collection.templates,
|
|
3481
|
+
documents: {
|
|
3482
|
+
pageInfo: {
|
|
3483
|
+
hasNextPage: !!response.nextCursor,
|
|
3484
|
+
hasPreviousPage: !!response.prevCursor,
|
|
3485
|
+
startCursor: "",
|
|
3486
|
+
endCursor: response.nextCursor || ""
|
|
3487
|
+
},
|
|
3488
|
+
edges
|
|
3489
|
+
}
|
|
3490
|
+
});
|
|
3491
|
+
} catch (error2) {
|
|
3492
|
+
cms.alerts.error(`[${error2.name}] GetCollection failed: ${error2.message}`);
|
|
3493
|
+
console.error(error2);
|
|
3494
|
+
setCollection(void 0);
|
|
3495
|
+
setError(error2);
|
|
3496
|
+
}
|
|
3497
|
+
setLoading(false);
|
|
3498
|
+
}
|
|
3499
|
+
};
|
|
3500
|
+
if (cancelled)
|
|
3501
|
+
return;
|
|
3502
|
+
setLoading(true);
|
|
3503
|
+
searchCollection();
|
|
3504
|
+
return () => {
|
|
3505
|
+
cancelled = true;
|
|
3506
|
+
};
|
|
3507
|
+
}, [
|
|
3508
|
+
cms,
|
|
3509
|
+
collectionName,
|
|
3510
|
+
folder.loading,
|
|
3511
|
+
folder.fullyQualifiedName,
|
|
3512
|
+
resetState,
|
|
3513
|
+
after,
|
|
3514
|
+
search
|
|
3515
|
+
]);
|
|
3516
|
+
const reFetchCollection = () => setResetSate((x) => x + 1);
|
|
3517
|
+
return { collection, loading, error, reFetchCollection, collectionExtra };
|
|
3518
|
+
};
|
|
3176
3519
|
const GetCollection = ({
|
|
3177
3520
|
cms,
|
|
3178
3521
|
collectionName,
|
|
@@ -3181,10 +3524,11 @@ This will work when developing locally but NOT when deployed to production.
|
|
|
3181
3524
|
startCursor,
|
|
3182
3525
|
sortKey,
|
|
3183
3526
|
children,
|
|
3184
|
-
filterArgs
|
|
3527
|
+
filterArgs,
|
|
3528
|
+
search
|
|
3185
3529
|
}) => {
|
|
3186
3530
|
const navigate = reactRouterDom.useNavigate();
|
|
3187
|
-
const { collection, loading, error, reFetchCollection, collectionExtra } = useGetCollection(cms, collectionName, includeDocuments, folder, startCursor || "", sortKey, filterArgs) || {};
|
|
3531
|
+
const { collection, loading, error, reFetchCollection, collectionExtra } = search ? useSearchCollection(cms, collectionName, includeDocuments, folder, startCursor || "", search) : useGetCollection(cms, collectionName, includeDocuments, folder, startCursor || "", sortKey, filterArgs) || {};
|
|
3188
3532
|
React.useEffect(() => {
|
|
3189
3533
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
3190
3534
|
if (loading)
|
|
@@ -3192,9 +3536,10 @@ This will work when developing locally but NOT when deployed to production.
|
|
|
3192
3536
|
const collectionDefinition = cms.api.tina.schema.getCollection(collection.name);
|
|
3193
3537
|
const allowCreate = (_c = (_b = (_a = collectionDefinition == null ? void 0 : collectionDefinition.ui) == null ? void 0 : _a.allowedActions) == null ? void 0 : _b.create) != null ? _c : true;
|
|
3194
3538
|
const allowDelete = (_f = (_e = (_d = collectionDefinition == null ? void 0 : collectionDefinition.ui) == null ? void 0 : _d.allowedActions) == null ? void 0 : _e.delete) != null ? _f : true;
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3539
|
+
const collectionResponse = collection;
|
|
3540
|
+
if (!allowCreate && !allowDelete && ((_h = (_g = collectionResponse.documents) == null ? void 0 : _g.edges) == null ? void 0 : _h.length) === 1 && ((_k = (_j = (_i = collectionResponse.documents) == null ? void 0 : _i.edges[0]) == null ? void 0 : _j.node) == null ? void 0 : _k.__typename) !== "Folder") {
|
|
3541
|
+
const doc = collectionResponse.documents.edges[0].node;
|
|
3542
|
+
handleNavigate(navigate, cms, collectionResponse, collectionDefinition, doc);
|
|
3198
3543
|
}
|
|
3199
3544
|
}, [(collection == null ? void 0 : collection.name) || "", loading]);
|
|
3200
3545
|
if (error) {
|
|
@@ -3323,13 +3668,14 @@ This will work when developing locally but NOT when deployed to production.
|
|
|
3323
3668
|
after: "",
|
|
3324
3669
|
booleanEquals: null
|
|
3325
3670
|
});
|
|
3326
|
-
const [activeSearch, setActiveSearch] = React__default["default"].useState(false);
|
|
3327
3671
|
const [endCursor, setEndCursor] = React.useState("");
|
|
3328
3672
|
const [prevCursors, setPrevCursors] = React.useState([]);
|
|
3329
3673
|
const [sortKey, setSortKey] = React.useState(isSSR ? "" : window.localStorage.getItem(`${LOCAL_STORAGE_KEY}.${collectionName}`) || JSON.stringify({
|
|
3330
3674
|
order: "asc",
|
|
3331
3675
|
name: ""
|
|
3332
3676
|
}));
|
|
3677
|
+
const [search, setSearch] = React.useState("");
|
|
3678
|
+
const [searchInput, setSearchInput] = React.useState("");
|
|
3333
3679
|
const { order = "asc", name: sortName } = JSON.parse(sortKey || "{}");
|
|
3334
3680
|
const [sortOrder, setSortOrder] = React.useState(order);
|
|
3335
3681
|
const loc = reactRouterDom.useLocation();
|
|
@@ -3374,25 +3720,20 @@ This will work when developing locally but NOT when deployed to production.
|
|
|
3374
3720
|
before: "",
|
|
3375
3721
|
after: "",
|
|
3376
3722
|
booleanEquals: null
|
|
3377
|
-
}
|
|
3723
|
+
},
|
|
3724
|
+
search
|
|
3378
3725
|
}, (collection, _loading, reFetchCollection, collectionExtra) => {
|
|
3379
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
3726
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
|
|
3380
3727
|
collection.documents.totalCount;
|
|
3381
3728
|
const documents = collection.documents.edges;
|
|
3382
3729
|
const admin = cms.api.admin;
|
|
3383
3730
|
const pageInfo = collection.documents.pageInfo;
|
|
3384
3731
|
const fields = (_a = collectionExtra.fields) == null ? void 0 : _a.filter((x) => ["string", "number", "datetime", "boolean"].includes(x.type));
|
|
3385
3732
|
const sortField = fields == null ? void 0 : fields.find((field) => field.name === sortName);
|
|
3386
|
-
const
|
|
3387
|
-
return ["string", "datetime", "boolean"].includes(x.type) && !x.list;
|
|
3388
|
-
});
|
|
3389
|
-
const filterField = filterFields == null ? void 0 : filterFields.find((x) => x.name === vars.filterField);
|
|
3390
|
-
const showStartsWith = (filterField == null ? void 0 : filterField.type) === "string" && !filterField.list;
|
|
3391
|
-
const showDateFilter = (filterField == null ? void 0 : filterField.type) === "datetime";
|
|
3392
|
-
const showBooleanToggle = (filterField == null ? void 0 : filterField.type) === "boolean" && !filterField.list;
|
|
3733
|
+
const searchEnabled = !!((_d = (_c = (_b = cms.api.tina.schema) == null ? void 0 : _b.config) == null ? void 0 : _c.config) == null ? void 0 : _d.search);
|
|
3393
3734
|
const collectionDefinition = cms.api.tina.schema.getCollection(collection.name);
|
|
3394
|
-
const allowCreate = (
|
|
3395
|
-
const allowDelete = (
|
|
3735
|
+
const allowCreate = (_g = (_f = (_e = collectionDefinition == null ? void 0 : collectionDefinition.ui) == null ? void 0 : _e.allowedActions) == null ? void 0 : _f.create) != null ? _g : true;
|
|
3736
|
+
const allowDelete = (_j = (_i = (_h = collectionDefinition == null ? void 0 : collectionDefinition.ui) == null ? void 0 : _h.allowedActions) == null ? void 0 : _i.delete) != null ? _j : true;
|
|
3396
3737
|
const folderView = folder.fullyQualifiedName !== "";
|
|
3397
3738
|
return /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null, deleteModalOpen && /* @__PURE__ */ React__default["default"].createElement(DeleteModal, {
|
|
3398
3739
|
filename: vars.relativePath,
|
|
@@ -3434,7 +3775,7 @@ This will work when developing locally but NOT when deployed to production.
|
|
|
3434
3775
|
},
|
|
3435
3776
|
close: () => setRenameModalOpen(false)
|
|
3436
3777
|
}), /* @__PURE__ */ React__default["default"].createElement(PageHeader, {
|
|
3437
|
-
isLocalMode: (
|
|
3778
|
+
isLocalMode: (_l = (_k = cms == null ? void 0 : cms.api) == null ? void 0 : _k.tina) == null ? void 0 : _l.isLocalMode
|
|
3438
3779
|
}, /* @__PURE__ */ React__default["default"].createElement("div", {
|
|
3439
3780
|
className: "w-full grid grid-flow-col items-end gap-4"
|
|
3440
3781
|
}, /* @__PURE__ */ React__default["default"].createElement("div", {
|
|
@@ -3442,8 +3783,8 @@ This will work when developing locally but NOT when deployed to production.
|
|
|
3442
3783
|
}, /* @__PURE__ */ React__default["default"].createElement("h3", {
|
|
3443
3784
|
className: "font-sans text-2xl text-gray-700"
|
|
3444
3785
|
}, collection.label ? collection.label : collection.name), /* @__PURE__ */ React__default["default"].createElement("div", {
|
|
3445
|
-
className: "flex gap-4 items-
|
|
3446
|
-
}, (fields == null ? void 0 : fields.length) > 0 && /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null, /* @__PURE__ */ React__default["default"].createElement("div", {
|
|
3786
|
+
className: "flex gap-4 items-start flex-wrap"
|
|
3787
|
+
}, (fields == null ? void 0 : fields.length) > 0 && /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null, !search && /* @__PURE__ */ React__default["default"].createElement("div", {
|
|
3447
3788
|
className: "flex flex-col gap-2 items-start"
|
|
3448
3789
|
}, /* @__PURE__ */ React__default["default"].createElement("label", {
|
|
3449
3790
|
htmlFor: "sort",
|
|
@@ -3488,152 +3829,22 @@ This will work when developing locally but NOT when deployed to production.
|
|
|
3488
3829
|
setSortOrder(val.order);
|
|
3489
3830
|
}
|
|
3490
3831
|
}
|
|
3491
|
-
})), /* @__PURE__ */ React__default["default"].createElement("form", {
|
|
3492
|
-
className: "flex flex-wrap gap-4 items-end"
|
|
3493
|
-
}, /* @__PURE__ */ React__default["default"].createElement("div", {
|
|
3494
|
-
className: "flex flex-shrink-0 flex-col gap-2 items-start"
|
|
3495
|
-
}, /* @__PURE__ */ React__default["default"].createElement("label", {
|
|
3496
|
-
htmlFor: "filter",
|
|
3497
|
-
className: "block font-sans text-xs font-semibold text-gray-500 whitespace-normal"
|
|
3498
|
-
}, "Filter by"), /* @__PURE__ */ React__default["default"].createElement(toolkit.Select, {
|
|
3499
|
-
name: "filter",
|
|
3500
|
-
options: [
|
|
3501
|
-
{
|
|
3502
|
-
label: "None",
|
|
3503
|
-
value: ""
|
|
3504
|
-
},
|
|
3505
|
-
...filterFields.map((x) => ({
|
|
3506
|
-
label: typeof x.label === "string" && x.label || x.name,
|
|
3507
|
-
value: x.name
|
|
3508
|
-
}))
|
|
3509
|
-
],
|
|
3510
|
-
input: {
|
|
3511
|
-
id: "filter",
|
|
3512
|
-
name: "filter",
|
|
3513
|
-
value: vars.filterField,
|
|
3514
|
-
onChange: (e) => {
|
|
3515
|
-
const val = e.target.value;
|
|
3516
|
-
setEndCursor("");
|
|
3517
|
-
setPrevCursors([]);
|
|
3518
|
-
setVars((old) => ({
|
|
3519
|
-
...old,
|
|
3520
|
-
filterField: val
|
|
3521
|
-
}));
|
|
3522
|
-
if (!val) {
|
|
3523
|
-
reFetchCollection();
|
|
3524
|
-
}
|
|
3525
|
-
}
|
|
3526
|
-
}
|
|
3527
|
-
})), showStartsWith && /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null, /* @__PURE__ */ React__default["default"].createElement("div", {
|
|
3528
|
-
className: "flex flex-shrink-0 flex-col gap-2 items-start"
|
|
3529
|
-
}, /* @__PURE__ */ React__default["default"].createElement("label", {
|
|
3530
|
-
htmlFor: "startsWith",
|
|
3531
|
-
className: "block font-sans text-xs font-semibold text-gray-500 whitespace-normal"
|
|
3532
|
-
}, "Starts with"), /* @__PURE__ */ React__default["default"].createElement(toolkit.Input, {
|
|
3533
|
-
name: "startsWith",
|
|
3534
|
-
id: "startsWith",
|
|
3535
|
-
value: vars.startsWith,
|
|
3536
|
-
onChange: (e) => {
|
|
3537
|
-
const val = e.target.value;
|
|
3538
|
-
setVars((old) => ({
|
|
3539
|
-
...old,
|
|
3540
|
-
startsWith: val,
|
|
3541
|
-
after: "",
|
|
3542
|
-
before: "",
|
|
3543
|
-
booleanEquals: null
|
|
3544
|
-
}));
|
|
3545
|
-
}
|
|
3546
|
-
}))), showDateFilter && /* @__PURE__ */ React__default["default"].createElement("div", {
|
|
3547
|
-
className: "flex flex-shrink-0 gap-4"
|
|
3548
|
-
}, /* @__PURE__ */ React__default["default"].createElement("div", {
|
|
3549
|
-
className: "flex flex-col gap-2 items-start"
|
|
3550
|
-
}, /* @__PURE__ */ React__default["default"].createElement("label", {
|
|
3551
|
-
htmlFor: "dateAfter",
|
|
3552
|
-
className: "block font-sans text-xs font-semibold text-gray-500 whitespace-normal"
|
|
3553
|
-
}, "After"), /* @__PURE__ */ React__default["default"].createElement(toolkit.ReactDateTimeWithStyles, {
|
|
3554
|
-
inputProps: {
|
|
3555
|
-
className: toolkit.textFieldClasses
|
|
3556
|
-
},
|
|
3557
|
-
value: vars.after,
|
|
3558
|
-
onChange: (e) => {
|
|
3559
|
-
setVars((old) => ({
|
|
3560
|
-
...old,
|
|
3561
|
-
after: typeof e.format === "function" ? e.format() : "",
|
|
3562
|
-
booleanEquals: null,
|
|
3563
|
-
startsWith: ""
|
|
3564
|
-
}));
|
|
3565
|
-
}
|
|
3566
3832
|
})), /* @__PURE__ */ React__default["default"].createElement("div", {
|
|
3567
|
-
className: "flex flex-col gap-2 items-start"
|
|
3568
|
-
}, /* @__PURE__ */ React__default["default"].createElement(
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
value: vars.before,
|
|
3576
|
-
onChange: (e) => {
|
|
3577
|
-
setVars((old) => ({
|
|
3578
|
-
...old,
|
|
3579
|
-
before: typeof e.format === "function" ? e.format() : "",
|
|
3580
|
-
booleanEquals: null,
|
|
3581
|
-
startsWith: ""
|
|
3582
|
-
}));
|
|
3583
|
-
}
|
|
3584
|
-
}))), showBooleanToggle && /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null, /* @__PURE__ */ React__default["default"].createElement("div", {
|
|
3585
|
-
className: "flex flex-col gap-2 items-start"
|
|
3586
|
-
}, /* @__PURE__ */ React__default["default"].createElement("label", {
|
|
3587
|
-
htmlFor: "toggle",
|
|
3833
|
+
className: "flex flex-1 flex-col gap-2 items-start w-full"
|
|
3834
|
+
}, searchEnabled ? /* @__PURE__ */ React__default["default"].createElement(SearchInput, {
|
|
3835
|
+
loading: _loading,
|
|
3836
|
+
search,
|
|
3837
|
+
setSearch,
|
|
3838
|
+
searchInput,
|
|
3839
|
+
setSearchInput
|
|
3840
|
+
}) : /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null, /* @__PURE__ */ React__default["default"].createElement("label", {
|
|
3588
3841
|
className: "block font-sans text-xs font-semibold text-gray-500 whitespace-normal"
|
|
3589
|
-
},
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
setVars((old) => ({
|
|
3596
|
-
...old,
|
|
3597
|
-
booleanEquals: !old.booleanEquals,
|
|
3598
|
-
after: "",
|
|
3599
|
-
before: "",
|
|
3600
|
-
startsWith: ""
|
|
3601
|
-
}));
|
|
3602
|
-
}
|
|
3603
|
-
},
|
|
3604
|
-
name: "toggle"
|
|
3605
|
-
}))), (showStartsWith || showDateFilter || showBooleanToggle) && /* @__PURE__ */ React__default["default"].createElement("div", {
|
|
3606
|
-
className: "flex gap-3"
|
|
3607
|
-
}, /* @__PURE__ */ React__default["default"].createElement(toolkit.Button, {
|
|
3608
|
-
onClick: () => {
|
|
3609
|
-
setActiveSearch(true);
|
|
3610
|
-
setEndCursor("");
|
|
3611
|
-
setPrevCursors([]);
|
|
3612
|
-
reFetchCollection();
|
|
3613
|
-
},
|
|
3614
|
-
variant: "primary",
|
|
3615
|
-
type: "submit"
|
|
3616
|
-
}, "Search", " ", /* @__PURE__ */ React__default["default"].createElement(BiSearch, {
|
|
3617
|
-
className: "w-5 h-full ml-1.5 opacity-70"
|
|
3618
|
-
})), (vars.startsWith || vars.after || vars.before || vars.booleanEquals) && /* @__PURE__ */ React__default["default"].createElement(toolkit.Button, {
|
|
3619
|
-
onClick: () => {
|
|
3620
|
-
setActiveSearch(false);
|
|
3621
|
-
setVars((old) => ({
|
|
3622
|
-
...old,
|
|
3623
|
-
filterField: "",
|
|
3624
|
-
startsWith: "",
|
|
3625
|
-
after: "",
|
|
3626
|
-
before: "",
|
|
3627
|
-
booleanEquals: null
|
|
3628
|
-
}));
|
|
3629
|
-
setEndCursor("");
|
|
3630
|
-
setPrevCursors([]);
|
|
3631
|
-
reFetchCollection();
|
|
3632
|
-
},
|
|
3633
|
-
variant: "white"
|
|
3634
|
-
}, "Clear", " ", /* @__PURE__ */ React__default["default"].createElement(BiX, {
|
|
3635
|
-
className: "w-5 h-full ml-1 opacity-70"
|
|
3636
|
-
}))))))), /* @__PURE__ */ React__default["default"].createElement("div", {
|
|
3842
|
+
}, "Search"), /* @__PURE__ */ React__default["default"].createElement(toolkit.Message, {
|
|
3843
|
+
link: "https://tina.io/docs/reference/search/overview",
|
|
3844
|
+
linkLabel: "Read The Docs",
|
|
3845
|
+
type: "info",
|
|
3846
|
+
size: "small"
|
|
3847
|
+
}, "Search not configured.")))))), /* @__PURE__ */ React__default["default"].createElement("div", {
|
|
3637
3848
|
className: "flex self-end justify-self-end"
|
|
3638
3849
|
}, !collection.templates && allowCreate && /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Link, {
|
|
3639
3850
|
to: `/${folder.fullyQualifiedName ? [
|
|
@@ -3658,7 +3869,7 @@ This will work when developing locally but NOT when deployed to production.
|
|
|
3658
3869
|
className: "table-auto shadow bg-white border-b border-gray-200 w-full max-w-full rounded-lg"
|
|
3659
3870
|
}, /* @__PURE__ */ React__default["default"].createElement("tbody", {
|
|
3660
3871
|
className: "divide-y divide-gray-150"
|
|
3661
|
-
},
|
|
3872
|
+
}, folder.name && !search && /* @__PURE__ */ React__default["default"].createElement("tr", null, /* @__PURE__ */ React__default["default"].createElement("td", {
|
|
3662
3873
|
colSpan: 5
|
|
3663
3874
|
}, /* @__PURE__ */ React__default["default"].createElement(Breadcrumb, {
|
|
3664
3875
|
folder,
|
|
@@ -3849,6 +4060,59 @@ This will work when developing locally but NOT when deployed to production.
|
|
|
3849
4060
|
}));
|
|
3850
4061
|
});
|
|
3851
4062
|
};
|
|
4063
|
+
const SearchInput = ({
|
|
4064
|
+
loading,
|
|
4065
|
+
search,
|
|
4066
|
+
setSearch,
|
|
4067
|
+
searchInput,
|
|
4068
|
+
setSearchInput
|
|
4069
|
+
}) => {
|
|
4070
|
+
const [searchLoaded, setSearchLoaded] = React.useState(false);
|
|
4071
|
+
React.useEffect(() => {
|
|
4072
|
+
if (loading) {
|
|
4073
|
+
setSearchLoaded(false);
|
|
4074
|
+
} else {
|
|
4075
|
+
setSearchLoaded(true);
|
|
4076
|
+
}
|
|
4077
|
+
}, [loading]);
|
|
4078
|
+
return /* @__PURE__ */ React__default["default"].createElement("form", {
|
|
4079
|
+
className: "flex flex-1 flex-col gap-2 items-start w-full"
|
|
4080
|
+
}, /* @__PURE__ */ React__default["default"].createElement("label", {
|
|
4081
|
+
htmlFor: "search",
|
|
4082
|
+
className: "block font-sans text-xs font-semibold text-gray-500 whitespace-normal"
|
|
4083
|
+
}, "Search"), /* @__PURE__ */ React__default["default"].createElement("div", {
|
|
4084
|
+
className: "flex flex-wrap items-center gap-3"
|
|
4085
|
+
}, /* @__PURE__ */ React__default["default"].createElement("div", {
|
|
4086
|
+
className: "flex-1 min-w-[200px]"
|
|
4087
|
+
}, /* @__PURE__ */ React__default["default"].createElement(toolkit.Input, {
|
|
4088
|
+
type: "text",
|
|
4089
|
+
name: "search",
|
|
4090
|
+
placeholder: "Search",
|
|
4091
|
+
value: searchInput,
|
|
4092
|
+
onChange: (e) => {
|
|
4093
|
+
setSearchInput(e.target.value);
|
|
4094
|
+
}
|
|
4095
|
+
})), /* @__PURE__ */ React__default["default"].createElement("div", {
|
|
4096
|
+
className: "flex gap-3"
|
|
4097
|
+
}, /* @__PURE__ */ React__default["default"].createElement(toolkit.Button, {
|
|
4098
|
+
onClick: () => {
|
|
4099
|
+
setSearch(searchInput);
|
|
4100
|
+
setSearchLoaded(false);
|
|
4101
|
+
},
|
|
4102
|
+
variant: "primary",
|
|
4103
|
+
type: "submit"
|
|
4104
|
+
}, "Search ", /* @__PURE__ */ React__default["default"].createElement(BiSearch, {
|
|
4105
|
+
className: "w-5 h-full ml-1.5 opacity-70"
|
|
4106
|
+
})), search && searchLoaded && /* @__PURE__ */ React__default["default"].createElement(toolkit.Button, {
|
|
4107
|
+
onClick: () => {
|
|
4108
|
+
setSearch("");
|
|
4109
|
+
setSearchInput("");
|
|
4110
|
+
},
|
|
4111
|
+
variant: "white"
|
|
4112
|
+
}, "Clear ", /* @__PURE__ */ React__default["default"].createElement(BiX, {
|
|
4113
|
+
className: "w-5 h-full ml-1 opacity-70"
|
|
4114
|
+
})))));
|
|
4115
|
+
};
|
|
3852
4116
|
const Breadcrumb = ({ folder, navigate, collectionName }) => {
|
|
3853
4117
|
const folderArray = folder.name.split("/");
|
|
3854
4118
|
return /* @__PURE__ */ React__default["default"].createElement("div", {
|
|
@@ -3959,14 +4223,14 @@ This will work when developing locally but NOT when deployed to production.
|
|
|
3959
4223
|
const createDocument = async (cms, collection, template, mutationInfo, folder, values) => {
|
|
3960
4224
|
const api = new TinaAdminApi(cms);
|
|
3961
4225
|
const { filename, ...leftover } = values;
|
|
3962
|
-
const
|
|
4226
|
+
const relativePath2 = `${folder ? `${folder}/` : ""}${filename}.${collection.format}`;
|
|
3963
4227
|
const params = api.schema.transformPayload(collection.name, {
|
|
3964
4228
|
_collection: collection.name,
|
|
3965
4229
|
...template && { _template: template.name },
|
|
3966
4230
|
...leftover
|
|
3967
4231
|
});
|
|
3968
4232
|
if (await api.isAuthenticated()) {
|
|
3969
|
-
await api.createDocument(collection
|
|
4233
|
+
await api.createDocument(collection, relativePath2, params);
|
|
3970
4234
|
} else {
|
|
3971
4235
|
const authMessage = `CreateDocument failed: User is no longer authenticated; please login and try again.`;
|
|
3972
4236
|
cms.alerts.error(authMessage);
|
|
@@ -4161,7 +4425,7 @@ This will work when developing locally but NOT when deployed to production.
|
|
|
4161
4425
|
onPristineChange: setFormIsPristine
|
|
4162
4426
|
})));
|
|
4163
4427
|
};
|
|
4164
|
-
const useGetDocument = (cms, collectionName,
|
|
4428
|
+
const useGetDocument = (cms, collectionName, relativePath2) => {
|
|
4165
4429
|
const api = new TinaAdminApi(cms);
|
|
4166
4430
|
const [document, setDocument] = React.useState(void 0);
|
|
4167
4431
|
const [loading, setLoading] = React.useState(true);
|
|
@@ -4170,7 +4434,7 @@ This will work when developing locally but NOT when deployed to production.
|
|
|
4170
4434
|
const fetchDocument = async () => {
|
|
4171
4435
|
if (api.isAuthenticated()) {
|
|
4172
4436
|
try {
|
|
4173
|
-
const response = await api.fetchDocument(collectionName,
|
|
4437
|
+
const response = await api.fetchDocument(collectionName, relativePath2);
|
|
4174
4438
|
setDocument(response.document);
|
|
4175
4439
|
} catch (error2) {
|
|
4176
4440
|
cms.alerts.error(`[${error2.name}] GetDocument failed: ${error2.message}`);
|
|
@@ -4183,16 +4447,16 @@ This will work when developing locally but NOT when deployed to production.
|
|
|
4183
4447
|
};
|
|
4184
4448
|
setLoading(true);
|
|
4185
4449
|
fetchDocument();
|
|
4186
|
-
}, [cms, collectionName,
|
|
4450
|
+
}, [cms, collectionName, relativePath2]);
|
|
4187
4451
|
return { document, loading, error };
|
|
4188
4452
|
};
|
|
4189
4453
|
const GetDocument = ({
|
|
4190
4454
|
cms,
|
|
4191
4455
|
collectionName,
|
|
4192
|
-
relativePath,
|
|
4456
|
+
relativePath: relativePath2,
|
|
4193
4457
|
children
|
|
4194
4458
|
}) => {
|
|
4195
|
-
const { document, loading, error } = useGetDocument(cms, collectionName,
|
|
4459
|
+
const { document, loading, error } = useGetDocument(cms, collectionName, relativePath2);
|
|
4196
4460
|
if (error) {
|
|
4197
4461
|
return /* @__PURE__ */ React__default["default"].createElement(FullscreenError, null);
|
|
4198
4462
|
}
|
|
@@ -4211,7 +4475,7 @@ This will work when developing locally but NOT when deployed to production.
|
|
|
4211
4475
|
folder,
|
|
4212
4476
|
includeDocuments: false
|
|
4213
4477
|
}, (collection) => {
|
|
4214
|
-
const
|
|
4478
|
+
const relativePath2 = `${filename.startsWith("~/") ? filename.substring(2) : filename}.${collection.format}`;
|
|
4215
4479
|
const mutationInfo = {
|
|
4216
4480
|
includeCollection: true,
|
|
4217
4481
|
includeTemplate: !!collection.templates
|
|
@@ -4219,7 +4483,7 @@ This will work when developing locally but NOT when deployed to production.
|
|
|
4219
4483
|
return /* @__PURE__ */ React__default["default"].createElement(GetDocument, {
|
|
4220
4484
|
cms,
|
|
4221
4485
|
collectionName: collection.name,
|
|
4222
|
-
relativePath
|
|
4486
|
+
relativePath: relativePath2
|
|
4223
4487
|
}, (document) => {
|
|
4224
4488
|
var _a;
|
|
4225
4489
|
return /* @__PURE__ */ React__default["default"].createElement(RenderForm$1, {
|
|
@@ -4233,11 +4497,11 @@ This will work when developing locally but NOT when deployed to production.
|
|
|
4233
4497
|
});
|
|
4234
4498
|
}));
|
|
4235
4499
|
};
|
|
4236
|
-
const updateDocument = async (cms,
|
|
4500
|
+
const updateDocument = async (cms, relativePath2, collection, mutationInfo, values) => {
|
|
4237
4501
|
const api = new TinaAdminApi(cms);
|
|
4238
4502
|
const params = api.schema.transformPayload(collection.name, values);
|
|
4239
4503
|
if (await api.isAuthenticated()) {
|
|
4240
|
-
await api.updateDocument(collection
|
|
4504
|
+
await api.updateDocument(collection, relativePath2, params);
|
|
4241
4505
|
} else {
|
|
4242
4506
|
const authMessage = `UpdateDocument failed: User is no longer authenticated; please login and try again.`;
|
|
4243
4507
|
cms.alerts.error(authMessage);
|
|
@@ -4256,7 +4520,7 @@ This will work when developing locally but NOT when deployed to production.
|
|
|
4256
4520
|
folder,
|
|
4257
4521
|
includeDocuments: false
|
|
4258
4522
|
}, (collection) => {
|
|
4259
|
-
const
|
|
4523
|
+
const relativePath2 = `${resolvedFile}.${collection.format}`;
|
|
4260
4524
|
const mutationInfo = {
|
|
4261
4525
|
includeCollection: true,
|
|
4262
4526
|
includeTemplate: !!collection.templates
|
|
@@ -4264,12 +4528,12 @@ This will work when developing locally but NOT when deployed to production.
|
|
|
4264
4528
|
return /* @__PURE__ */ React__default["default"].createElement(PageWrapper, null, /* @__PURE__ */ React__default["default"].createElement(GetDocument, {
|
|
4265
4529
|
cms,
|
|
4266
4530
|
collectionName: collection.name,
|
|
4267
|
-
relativePath
|
|
4531
|
+
relativePath: relativePath2
|
|
4268
4532
|
}, (document) => /* @__PURE__ */ React__default["default"].createElement(RenderForm, {
|
|
4269
4533
|
cms,
|
|
4270
4534
|
document,
|
|
4271
4535
|
filename: resolvedFile,
|
|
4272
|
-
relativePath,
|
|
4536
|
+
relativePath: relativePath2,
|
|
4273
4537
|
collection,
|
|
4274
4538
|
mutationInfo
|
|
4275
4539
|
})));
|
|
@@ -4279,14 +4543,14 @@ This will work when developing locally but NOT when deployed to production.
|
|
|
4279
4543
|
cms,
|
|
4280
4544
|
document,
|
|
4281
4545
|
filename,
|
|
4282
|
-
relativePath,
|
|
4546
|
+
relativePath: relativePath2,
|
|
4283
4547
|
collection,
|
|
4284
4548
|
mutationInfo
|
|
4285
4549
|
}) => {
|
|
4286
4550
|
var _a, _b;
|
|
4287
4551
|
const [formIsPristine, setFormIsPristine] = React.useState(true);
|
|
4288
4552
|
const schema = cms.api.tina.schema;
|
|
4289
|
-
const parentFolder2 =
|
|
4553
|
+
const parentFolder2 = relativePath2.split("/").slice(0, -1).join("/");
|
|
4290
4554
|
const schemaCollection = schema.getCollection(collection.name);
|
|
4291
4555
|
const template = schema.getTemplateForData({
|
|
4292
4556
|
collection: schemaCollection,
|
|
@@ -4306,7 +4570,7 @@ This will work when developing locally but NOT when deployed to production.
|
|
|
4306
4570
|
initialValues: document._values,
|
|
4307
4571
|
onSubmit: async (values) => {
|
|
4308
4572
|
try {
|
|
4309
|
-
await updateDocument(cms,
|
|
4573
|
+
await updateDocument(cms, relativePath2, collection, mutationInfo, values);
|
|
4310
4574
|
cms.alerts.success("Document updated!");
|
|
4311
4575
|
} catch (error) {
|
|
4312
4576
|
console.error(error);
|
|
@@ -4314,7 +4578,7 @@ This will work when developing locally but NOT when deployed to production.
|
|
|
4314
4578
|
}
|
|
4315
4579
|
}
|
|
4316
4580
|
});
|
|
4317
|
-
}, [cms, document,
|
|
4581
|
+
}, [cms, document, relativePath2, collection, mutationInfo]);
|
|
4318
4582
|
const navBreakpoint = 1e3;
|
|
4319
4583
|
const windowWidth = windowSize.useWindowWidth();
|
|
4320
4584
|
const renderNavToggle = windowWidth < navBreakpoint + 1;
|
|
@@ -4641,10 +4905,12 @@ This will work when developing locally but NOT when deployed to production.
|
|
|
4641
4905
|
exports2.Client = Client;
|
|
4642
4906
|
exports2.DEFAULT_LOCAL_TINA_GQL_SERVER_URL = DEFAULT_LOCAL_TINA_GQL_SERVER_URL;
|
|
4643
4907
|
exports2.LocalClient = LocalClient;
|
|
4908
|
+
exports2.LocalSearchClient = LocalSearchClient;
|
|
4644
4909
|
exports2.RouteMappingPlugin = RouteMappingPlugin;
|
|
4645
4910
|
exports2.TinaAdmin = TinaAdmin;
|
|
4646
4911
|
exports2.TinaAdminApi = TinaAdminApi;
|
|
4647
4912
|
exports2.TinaCMSProvider2 = TinaCMSProvider2;
|
|
4913
|
+
exports2.TinaCMSSearchClient = TinaCMSSearchClient;
|
|
4648
4914
|
exports2.TinaCloudAuthWall = TinaCloudAuthWall;
|
|
4649
4915
|
exports2.TinaCloudProvider = TinaCloudProvider;
|
|
4650
4916
|
exports2.assertShape = assertShape;
|