meadow-endpoints 4.0.7 → 4.0.10
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/CONTRIBUTING.md +50 -0
- package/README.md +172 -51
- package/dist/indoctrinate_content_staging/Indoctrinate-Catalog-AppData.json +4548 -0
- package/docs/README.md +326 -0
- package/docs/_sidebar.md +37 -0
- package/docs/crud/README.md +220 -0
- package/docs/crud/count.md +168 -0
- package/docs/crud/create.md +194 -0
- package/docs/crud/delete.md +237 -0
- package/docs/crud/read.md +324 -0
- package/docs/crud/schema.md +349 -0
- package/docs/crud/update.md +203 -0
- package/docs/css/docuserve.css +73 -0
- package/docs/index.html +39 -0
- package/docs/retold-catalog.json +177 -0
- package/docs/retold-keyword-index.json +6720 -0
- package/package.json +21 -28
- package/source/endpoints/update/Meadow-Operation-Update.js +9 -1
- package/test/MeadowEndpoints_basic_tests.js +1586 -37
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# Update Endpoints
|
|
2
|
+
|
|
3
|
+
> Modify existing records with automatic conflict detection
|
|
4
|
+
|
|
5
|
+
The Update endpoints handle single-record updates, bulk updates, upserts (insert-or-update), and bulk upserts. The Update operation reads the existing record before writing, providing a checkpoint for authorization.
|
|
6
|
+
|
|
7
|
+
## Routes
|
|
8
|
+
|
|
9
|
+
| Method | Route | Description |
|
|
10
|
+
|--------|-------|-------------|
|
|
11
|
+
| PUT | `/{v}/{entity}` | Update a single record |
|
|
12
|
+
| PUT | `/{v}/{entity}/s` | Bulk update (array of records) |
|
|
13
|
+
| PUT | `/{v}/{entity}/Upsert` | Insert or update a record |
|
|
14
|
+
| PUT | `/{v}/{entity}/Upserts` | Bulk upsert (array of records) |
|
|
15
|
+
|
|
16
|
+
## Single Update
|
|
17
|
+
|
|
18
|
+
**Request:** `PUT /1.0/Book`
|
|
19
|
+
|
|
20
|
+
The request body must include the record's default identifier (e.g., `IDBook`):
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"IDBook": 42,
|
|
25
|
+
"Title": "Dune (Revised Edition)",
|
|
26
|
+
"Author": "Frank Herbert"
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Response:** The complete updated record, re-read from the database:
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"IDBook": 42,
|
|
35
|
+
"GUIDBook": "0x12ab34cd...",
|
|
36
|
+
"Title": "Dune (Revised Edition)",
|
|
37
|
+
"Author": "Frank Herbert",
|
|
38
|
+
"CreateDate": "2024-01-15T10:30:00.000Z",
|
|
39
|
+
"CreatingIDUser": 1,
|
|
40
|
+
"UpdateDate": "2024-03-20T14:15:00.000Z",
|
|
41
|
+
"UpdatingIDUser": 1,
|
|
42
|
+
"Deleted": 0
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Bulk Update
|
|
47
|
+
|
|
48
|
+
**Request:** `PUT /1.0/Book/s`
|
|
49
|
+
|
|
50
|
+
Send an array of records, each including its identifier:
|
|
51
|
+
|
|
52
|
+
```json
|
|
53
|
+
[
|
|
54
|
+
{ "IDBook": 42, "Title": "Dune (Revised Edition)" },
|
|
55
|
+
{ "IDBook": 43, "Title": "Neuromancer (2nd Edition)" }
|
|
56
|
+
]
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**Response:** An array of updated records. Each record passes through the full Update lifecycle individually.
|
|
60
|
+
|
|
61
|
+
## Upsert
|
|
62
|
+
|
|
63
|
+
**Request:** `PUT /1.0/Book/Upsert`
|
|
64
|
+
|
|
65
|
+
If the record has a valid identifier and that record exists, it is updated. Otherwise, it is created:
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"IDBook": 0,
|
|
70
|
+
"Title": "New Book",
|
|
71
|
+
"Author": "New Author"
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The Upsert endpoint first attempts a read. If the record is not found, it falls through to the Create operation. If found, it performs an Update.
|
|
76
|
+
|
|
77
|
+
## Bulk Upsert
|
|
78
|
+
|
|
79
|
+
**Request:** `PUT /1.0/Book/Upserts`
|
|
80
|
+
|
|
81
|
+
An array of records to upsert:
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
[
|
|
85
|
+
{ "IDBook": 42, "Title": "Updated Title" },
|
|
86
|
+
{ "IDBook": 0, "Title": "Brand New Book", "Author": "New Author" }
|
|
87
|
+
]
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Request Lifecycle
|
|
91
|
+
|
|
92
|
+
The Update operation delegates to `Meadow-Operation-Update`, which runs the following waterfall:
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
PUT /{v}/{entity}
|
|
96
|
+
|
|
|
97
|
+
v
|
|
98
|
+
Validate request body is an object
|
|
99
|
+
Validate record has a valid ID (> 0)
|
|
100
|
+
|
|
|
101
|
+
v
|
|
102
|
+
Read existing record (DAL.doRead) <-- loads current state for security checks
|
|
103
|
+
|
|
|
104
|
+
v
|
|
105
|
+
Build update query: addRecord(record), setIDUser(SessionData.UserID)
|
|
106
|
+
|
|
|
107
|
+
v
|
|
108
|
+
DAL.doUpdate(query) <-- execute update + re-read
|
|
109
|
+
|
|
|
110
|
+
v
|
|
111
|
+
[Update-PostOperation] <-- audit, notify, transform
|
|
112
|
+
|
|
|
113
|
+
v
|
|
114
|
+
Send response (updated record)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Behavior Injection Points
|
|
118
|
+
|
|
119
|
+
### Update-PostOperation
|
|
120
|
+
|
|
121
|
+
The Update operation has **only a post-operation hook** -- there is no pre-operation or query-configuration injection point. The existing record is loaded and used for the update automatically.
|
|
122
|
+
|
|
123
|
+
The hook runs after the record has been updated and re-read from the database. The updated record is available on `pRequestState.Record`.
|
|
124
|
+
|
|
125
|
+
```javascript
|
|
126
|
+
tmpEndpoints.controller.BehaviorInjection.setBehavior('Update-PostOperation',
|
|
127
|
+
(pRequest, pRequestState, fCallback) =>
|
|
128
|
+
{
|
|
129
|
+
// Audit the update
|
|
130
|
+
let tmpAuditRecord = {
|
|
131
|
+
Action: 'Update',
|
|
132
|
+
EntityType: 'Book',
|
|
133
|
+
EntityID: pRequestState.Record.IDBook,
|
|
134
|
+
UserID: pRequestState.SessionData.UserID
|
|
135
|
+
};
|
|
136
|
+
_Fable.log.info(`Book updated: ${JSON.stringify(tmpAuditRecord)}`);
|
|
137
|
+
return fCallback();
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Why No Pre-Operation Hook?
|
|
142
|
+
|
|
143
|
+
The Update operation reads the existing record before performing the update as an inherent part of its workflow. The original record is accessible via `pRequestState.OriginalRecord` (when using cached records) or loaded via `DAL.doRead()`. Authorization checks that need the original record state can use the `Update-PostOperation` hook to compare the original and updated records, or use a custom endpoint for more complex scenarios.
|
|
144
|
+
|
|
145
|
+
## Automatic Field Handling
|
|
146
|
+
|
|
147
|
+
| Field | Behavior |
|
|
148
|
+
|-------|----------|
|
|
149
|
+
| `UpdateDate` | Set automatically by the DAL on every update |
|
|
150
|
+
| `UpdatingIDUser` | Set from `Query.IDUser` (from `SessionData.UserID`) |
|
|
151
|
+
| `CreateDate` | Preserved from original record |
|
|
152
|
+
| `CreatingIDUser` | Preserved from original record |
|
|
153
|
+
|
|
154
|
+
## Error Handling
|
|
155
|
+
|
|
156
|
+
The Update endpoint validates two conditions before attempting the update:
|
|
157
|
+
|
|
158
|
+
1. **Request body must be an object** - Returns `400` if not
|
|
159
|
+
2. **Record ID must be valid (> 0)** - Returns `400` if missing or invalid
|
|
160
|
+
|
|
161
|
+
If the existing record is not found during the pre-update read, a `404` error is returned.
|
|
162
|
+
|
|
163
|
+
For bulk updates, individual record errors are captured per-record without halting the batch:
|
|
164
|
+
|
|
165
|
+
```json
|
|
166
|
+
[
|
|
167
|
+
{ "IDBook": 42, "Title": "Updated Successfully", ... },
|
|
168
|
+
{ "IDBook": 999, "Error": { "Code": 404, "Message": "Record not Found" } }
|
|
169
|
+
]
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Real-World Example: Computed Field Update
|
|
173
|
+
|
|
174
|
+
```javascript
|
|
175
|
+
tmpEndpoints.controller.BehaviorInjection.setBehavior('Update-PostOperation',
|
|
176
|
+
(pRequest, pRequestState, fCallback) =>
|
|
177
|
+
{
|
|
178
|
+
// After updating an order line item, recalculate the order total
|
|
179
|
+
if (pRequestState.Record.IDOrder)
|
|
180
|
+
{
|
|
181
|
+
let tmpQuery = _OrderDAL.query;
|
|
182
|
+
tmpQuery.addFilter('IDOrder', pRequestState.Record.IDOrder);
|
|
183
|
+
|
|
184
|
+
_OrderLineDAL.doReads(tmpQuery,
|
|
185
|
+
(pError, pQuery, pRecords) =>
|
|
186
|
+
{
|
|
187
|
+
if (pError) return fCallback();
|
|
188
|
+
|
|
189
|
+
let tmpTotal = pRecords.reduce(
|
|
190
|
+
(pSum, pLine) => pSum + (pLine.Quantity * pLine.UnitPrice), 0);
|
|
191
|
+
|
|
192
|
+
let tmpUpdateQuery = _OrderDAL.query;
|
|
193
|
+
tmpUpdateQuery.addRecord({ IDOrder: pRequestState.Record.IDOrder, Total: tmpTotal });
|
|
194
|
+
_OrderDAL.doUpdate(tmpUpdateQuery,
|
|
195
|
+
(pError) => fCallback());
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
else
|
|
199
|
+
{
|
|
200
|
+
return fCallback();
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
```
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/* ============================================================================
|
|
2
|
+
Pict Docuserve - Base Styles
|
|
3
|
+
============================================================================ */
|
|
4
|
+
|
|
5
|
+
/* Reset and base */
|
|
6
|
+
*, *::before, *::after {
|
|
7
|
+
box-sizing: border-box;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
html, body {
|
|
11
|
+
margin: 0;
|
|
12
|
+
padding: 0;
|
|
13
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
14
|
+
font-size: 16px;
|
|
15
|
+
line-height: 1.5;
|
|
16
|
+
color: #423D37;
|
|
17
|
+
background-color: #fff;
|
|
18
|
+
-webkit-font-smoothing: antialiased;
|
|
19
|
+
-moz-osx-font-smoothing: grayscale;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* Typography */
|
|
23
|
+
h1, h2, h3, h4, h5, h6 {
|
|
24
|
+
margin-top: 0;
|
|
25
|
+
line-height: 1.3;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
a {
|
|
29
|
+
color: #2E7D74;
|
|
30
|
+
text-decoration: none;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
a:hover {
|
|
34
|
+
color: #256861;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* Application container */
|
|
38
|
+
#Docuserve-Application-Container {
|
|
39
|
+
min-height: 100vh;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* Utility: scrollbar styling */
|
|
43
|
+
::-webkit-scrollbar {
|
|
44
|
+
width: 8px;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
::-webkit-scrollbar-track {
|
|
48
|
+
background: #F5F0E8;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
::-webkit-scrollbar-thumb {
|
|
52
|
+
background: #D4CCBE;
|
|
53
|
+
border-radius: 4px;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
::-webkit-scrollbar-thumb:hover {
|
|
57
|
+
background: #B5AA9A;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/* Responsive adjustments */
|
|
61
|
+
@media (max-width: 768px) {
|
|
62
|
+
html {
|
|
63
|
+
font-size: 14px;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
#Docuserve-Sidebar-Container {
|
|
67
|
+
display: none;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.docuserve-body {
|
|
71
|
+
flex-direction: column;
|
|
72
|
+
}
|
|
73
|
+
}
|
package/docs/index.html
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
7
|
+
<meta name="description" content="Documentation powered by pict-docuserve">
|
|
8
|
+
|
|
9
|
+
<title>Documentation</title>
|
|
10
|
+
|
|
11
|
+
<!-- Application Stylesheet -->
|
|
12
|
+
<link href="css/docuserve.css" rel="stylesheet">
|
|
13
|
+
<!-- KaTeX stylesheet for LaTeX equation rendering -->
|
|
14
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/katex.min.css">
|
|
15
|
+
<!-- PICT Dynamic View CSS Container -->
|
|
16
|
+
<style id="PICT-CSS"></style>
|
|
17
|
+
|
|
18
|
+
<!-- Load the PICT library from jsDelivr CDN -->
|
|
19
|
+
<script src="https://cdn.jsdelivr.net/npm/pict@1/dist/pict.min.js" type="text/javascript"></script>
|
|
20
|
+
<!-- Bootstrap the Application -->
|
|
21
|
+
<script type="text/javascript">
|
|
22
|
+
//<![CDATA[
|
|
23
|
+
Pict.safeOnDocumentReady(() => { Pict.safeLoadPictApplication(PictDocuserve, 2)});
|
|
24
|
+
//]]>
|
|
25
|
+
</script>
|
|
26
|
+
</head>
|
|
27
|
+
<body>
|
|
28
|
+
<!-- The root container for the Pict application -->
|
|
29
|
+
<div id="Docuserve-Application-Container"></div>
|
|
30
|
+
|
|
31
|
+
<!-- Mermaid diagram rendering -->
|
|
32
|
+
<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
|
|
33
|
+
<script>mermaid.initialize({ startOnLoad: false, theme: 'default' });</script>
|
|
34
|
+
<!-- KaTeX for LaTeX equation rendering -->
|
|
35
|
+
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/katex.min.js"></script>
|
|
36
|
+
<!-- Load the Docuserve PICT Application Bundle from jsDelivr CDN -->
|
|
37
|
+
<script src="https://cdn.jsdelivr.net/npm/pict-docuserve@0/dist/pict-docuserve.min.js" type="text/javascript"></script>
|
|
38
|
+
</body>
|
|
39
|
+
</html>
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Generated": "2026-02-18T03:27:45.413Z",
|
|
3
|
+
"GitHubOrg": "stevenvelozo",
|
|
4
|
+
"DefaultBranch": "master",
|
|
5
|
+
"Groups": [
|
|
6
|
+
{
|
|
7
|
+
"Name": ".config",
|
|
8
|
+
"Key": ".config",
|
|
9
|
+
"Description": "",
|
|
10
|
+
"Modules": [
|
|
11
|
+
{
|
|
12
|
+
"Name": "code-server",
|
|
13
|
+
"Repo": "code-server",
|
|
14
|
+
"Group": ".config",
|
|
15
|
+
"Branch": "master",
|
|
16
|
+
"HasDocs": false,
|
|
17
|
+
"HasCover": false,
|
|
18
|
+
"Sidebar": [],
|
|
19
|
+
"DocFiles": []
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"Name": "configstore",
|
|
23
|
+
"Repo": "configstore",
|
|
24
|
+
"Group": ".config",
|
|
25
|
+
"Branch": "master",
|
|
26
|
+
"HasDocs": false,
|
|
27
|
+
"HasCover": false,
|
|
28
|
+
"Sidebar": [],
|
|
29
|
+
"DocFiles": []
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"Name": "luxury-extras",
|
|
33
|
+
"Repo": "luxury-extras",
|
|
34
|
+
"Group": ".config",
|
|
35
|
+
"Branch": "master",
|
|
36
|
+
"HasDocs": false,
|
|
37
|
+
"HasCover": false,
|
|
38
|
+
"Sidebar": [],
|
|
39
|
+
"DocFiles": []
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"Name": "vscode-sqltools",
|
|
43
|
+
"Repo": "vscode-sqltools",
|
|
44
|
+
"Group": ".config",
|
|
45
|
+
"Branch": "master",
|
|
46
|
+
"HasDocs": false,
|
|
47
|
+
"HasCover": false,
|
|
48
|
+
"Sidebar": [],
|
|
49
|
+
"DocFiles": []
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"Name": ".github",
|
|
55
|
+
"Key": ".github",
|
|
56
|
+
"Description": "",
|
|
57
|
+
"Modules": [
|
|
58
|
+
{
|
|
59
|
+
"Name": "workflows",
|
|
60
|
+
"Repo": "workflows",
|
|
61
|
+
"Group": ".github",
|
|
62
|
+
"Branch": "master",
|
|
63
|
+
"HasDocs": false,
|
|
64
|
+
"HasCover": false,
|
|
65
|
+
"Sidebar": [],
|
|
66
|
+
"DocFiles": []
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"Name": "Dist",
|
|
72
|
+
"Key": "dist",
|
|
73
|
+
"Description": "",
|
|
74
|
+
"Modules": [
|
|
75
|
+
{
|
|
76
|
+
"Name": "indoctrinate_content_staging",
|
|
77
|
+
"Repo": "indoctrinate_content_staging",
|
|
78
|
+
"Group": "dist",
|
|
79
|
+
"Branch": "master",
|
|
80
|
+
"HasDocs": false,
|
|
81
|
+
"HasCover": false,
|
|
82
|
+
"Sidebar": [],
|
|
83
|
+
"DocFiles": []
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"Name": "Docs",
|
|
89
|
+
"Key": "docs",
|
|
90
|
+
"Description": "",
|
|
91
|
+
"Modules": [
|
|
92
|
+
{
|
|
93
|
+
"Name": "crud",
|
|
94
|
+
"Repo": "crud",
|
|
95
|
+
"Group": "docs",
|
|
96
|
+
"Branch": "master",
|
|
97
|
+
"HasDocs": true,
|
|
98
|
+
"HasCover": false,
|
|
99
|
+
"Sidebar": [],
|
|
100
|
+
"DocFiles": [
|
|
101
|
+
"crud/README.md",
|
|
102
|
+
"crud/count.md",
|
|
103
|
+
"crud/create.md",
|
|
104
|
+
"crud/delete.md",
|
|
105
|
+
"crud/read.md",
|
|
106
|
+
"crud/schema.md",
|
|
107
|
+
"crud/update.md"
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
]
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"Name": "Source",
|
|
114
|
+
"Key": "source",
|
|
115
|
+
"Description": "",
|
|
116
|
+
"Modules": [
|
|
117
|
+
{
|
|
118
|
+
"Name": "controller",
|
|
119
|
+
"Repo": "controller",
|
|
120
|
+
"Group": "source",
|
|
121
|
+
"Branch": "master",
|
|
122
|
+
"HasDocs": false,
|
|
123
|
+
"HasCover": false,
|
|
124
|
+
"Sidebar": [],
|
|
125
|
+
"DocFiles": []
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"Name": "endpoints",
|
|
129
|
+
"Repo": "endpoints",
|
|
130
|
+
"Group": "source",
|
|
131
|
+
"Branch": "master",
|
|
132
|
+
"HasDocs": false,
|
|
133
|
+
"HasCover": false,
|
|
134
|
+
"Sidebar": [],
|
|
135
|
+
"DocFiles": []
|
|
136
|
+
}
|
|
137
|
+
]
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"Name": "Test_support",
|
|
141
|
+
"Key": "test_support",
|
|
142
|
+
"Description": "",
|
|
143
|
+
"Modules": [
|
|
144
|
+
{
|
|
145
|
+
"Name": "data",
|
|
146
|
+
"Repo": "data",
|
|
147
|
+
"Group": "test_support",
|
|
148
|
+
"Branch": "master",
|
|
149
|
+
"HasDocs": false,
|
|
150
|
+
"HasCover": false,
|
|
151
|
+
"Sidebar": [],
|
|
152
|
+
"DocFiles": []
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
"Name": "model",
|
|
156
|
+
"Repo": "model",
|
|
157
|
+
"Group": "test_support",
|
|
158
|
+
"Branch": "master",
|
|
159
|
+
"HasDocs": false,
|
|
160
|
+
"HasCover": false,
|
|
161
|
+
"Sidebar": [],
|
|
162
|
+
"DocFiles": []
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"Name": "test_old",
|
|
166
|
+
"Repo": "test_old",
|
|
167
|
+
"Group": "test_support",
|
|
168
|
+
"Branch": "master",
|
|
169
|
+
"HasDocs": false,
|
|
170
|
+
"HasCover": false,
|
|
171
|
+
"Sidebar": [],
|
|
172
|
+
"DocFiles": []
|
|
173
|
+
}
|
|
174
|
+
]
|
|
175
|
+
}
|
|
176
|
+
]
|
|
177
|
+
}
|