@kineticdata/react 6.1.6 → 7.0.0-rc1

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.
@@ -0,0 +1,276 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault")["default"];
4
+ var _axios = _interopRequireDefault(require("axios"));
5
+ var _customIndexes = require("./customIndexes");
6
+ var _promises = require("../../../tests/utils/promises");
7
+ jest.mock('../../helpers', function () {
8
+ return {
9
+ bundle: {
10
+ apiLocation: function apiLocation() {
11
+ return 'app/api/v1';
12
+ },
13
+ kappSlug: function kappSlug() {
14
+ return 'mock-kapp';
15
+ }
16
+ }
17
+ };
18
+ });
19
+ var sampleIndex = {
20
+ id: '00000000-0000-0000-0000-000000000001',
21
+ name: 'Unique email per form',
22
+ unique: true,
23
+ status: 'Built',
24
+ errorMessage: null,
25
+ parts: [{
26
+ type: 'value',
27
+ name: 'Email',
28
+ key: 'email'
29
+ }],
30
+ createdAt: '2026-05-14T00:00:00Z',
31
+ createdBy: 'admin',
32
+ updatedAt: '2026-05-14T00:00:00Z',
33
+ updatedBy: 'admin'
34
+ };
35
+ describe('customIndexes api', function () {
36
+ describe('#fetchCustomIndexes', function () {
37
+ describe('when successful', function () {
38
+ beforeEach(function () {
39
+ _axios["default"].get = (0, _promises.resolvePromiseWith)({
40
+ status: 200,
41
+ data: {
42
+ indexes: [sampleIndex]
43
+ }
44
+ });
45
+ });
46
+ test('returns indexes array', function () {
47
+ expect.assertions(2);
48
+ return (0, _customIndexes.fetchCustomIndexes)({
49
+ kappSlug: 'k',
50
+ formSlug: 'f'
51
+ }).then(function (_ref) {
52
+ var indexes = _ref.indexes,
53
+ error = _ref.error;
54
+ expect(error).toBeUndefined();
55
+ expect(indexes).toEqual([sampleIndex]);
56
+ });
57
+ });
58
+ test('targets the form-scoped indexes URL', function () {
59
+ expect.assertions(1);
60
+ return (0, _customIndexes.fetchCustomIndexes)({
61
+ kappSlug: 'k',
62
+ formSlug: 'f'
63
+ }).then(function () {
64
+ expect(_axios["default"].get).toHaveBeenCalledWith('app/api/v1/kapps/k/forms/f/indexes', expect.any(Object));
65
+ });
66
+ });
67
+ });
68
+ test('throws when required options are missing', function () {
69
+ expect(function () {
70
+ return (0, _customIndexes.fetchCustomIndexes)({
71
+ kappSlug: 'k'
72
+ });
73
+ }).toThrow();
74
+ });
75
+ });
76
+ describe('#createCustomIndex', function () {
77
+ describe('when successful', function () {
78
+ beforeEach(function () {
79
+ _axios["default"].post = (0, _promises.resolvePromiseWith)({
80
+ status: 201,
81
+ data: {
82
+ index: sampleIndex
83
+ }
84
+ });
85
+ });
86
+ test('returns the created index', function () {
87
+ expect.assertions(2);
88
+ return (0, _customIndexes.createCustomIndex)({
89
+ kappSlug: 'k',
90
+ formSlug: 'f',
91
+ index: {
92
+ name: 'Unique email per form',
93
+ unique: true,
94
+ parts: [{
95
+ type: 'value',
96
+ name: 'Email'
97
+ }]
98
+ }
99
+ }).then(function (_ref2) {
100
+ var index = _ref2.index,
101
+ error = _ref2.error;
102
+ expect(error).toBeUndefined();
103
+ expect(index).toEqual(sampleIndex);
104
+ });
105
+ });
106
+ test('strips read-only key from parts before POSTing', function () {
107
+ expect.assertions(1);
108
+ return (0, _customIndexes.createCustomIndex)({
109
+ kappSlug: 'k',
110
+ formSlug: 'f',
111
+ index: {
112
+ name: 'X',
113
+ unique: false,
114
+ parts: [{
115
+ type: 'value',
116
+ name: 'Email',
117
+ key: 'email'
118
+ }]
119
+ }
120
+ }).then(function () {
121
+ expect(_axios["default"].post).toHaveBeenCalledWith('app/api/v1/kapps/k/forms/f/indexes', {
122
+ name: 'X',
123
+ unique: false,
124
+ parts: [{
125
+ type: 'value',
126
+ name: 'Email'
127
+ }]
128
+ }, expect.any(Object));
129
+ });
130
+ });
131
+ });
132
+ describe('when 422 (cap reached)', function () {
133
+ beforeEach(function () {
134
+ _axios["default"].post = (0, _promises.rejectPromiseWith)({
135
+ response: {
136
+ status: 422,
137
+ statusText: 'Unprocessable Entity',
138
+ headers: {
139
+ 'content-type': 'application/json'
140
+ },
141
+ data: {
142
+ error: 'Per-form custom-index cap reached'
143
+ }
144
+ }
145
+ });
146
+ });
147
+ test('returns error with statusCode 422', function () {
148
+ expect.assertions(2);
149
+ return (0, _customIndexes.createCustomIndex)({
150
+ kappSlug: 'k',
151
+ formSlug: 'f',
152
+ index: {
153
+ name: 'X',
154
+ parts: [{
155
+ type: 'value',
156
+ name: 'A'
157
+ }]
158
+ }
159
+ }).then(function (_ref3) {
160
+ var error = _ref3.error;
161
+ expect(error.statusCode).toBe(422);
162
+ expect(error.message).toBe('Per-form custom-index cap reached');
163
+ });
164
+ });
165
+ });
166
+ describe('when 502 (Postgres rejection)', function () {
167
+ beforeEach(function () {
168
+ _axios["default"].post = (0, _promises.rejectPromiseWith)({
169
+ response: {
170
+ status: 502,
171
+ statusText: 'Bad Gateway',
172
+ headers: {
173
+ 'content-type': 'application/json'
174
+ },
175
+ data: {
176
+ error: 'duplicate key value violates unique constraint'
177
+ }
178
+ }
179
+ });
180
+ });
181
+ test('returns error with statusCode 502 and the Postgres message', function () {
182
+ expect.assertions(2);
183
+ return (0, _customIndexes.createCustomIndex)({
184
+ kappSlug: 'k',
185
+ formSlug: 'f',
186
+ index: {
187
+ name: 'X',
188
+ parts: [{
189
+ type: 'value',
190
+ name: 'A'
191
+ }]
192
+ }
193
+ }).then(function (_ref4) {
194
+ var error = _ref4.error;
195
+ expect(error.statusCode).toBe(502);
196
+ expect(error.message).toMatch(/duplicate key/);
197
+ });
198
+ });
199
+ });
200
+ test('throws when required options are missing', function () {
201
+ expect(function () {
202
+ return (0, _customIndexes.createCustomIndex)({
203
+ kappSlug: 'k',
204
+ formSlug: 'f'
205
+ });
206
+ }).toThrow();
207
+ });
208
+ });
209
+ describe('#deleteCustomIndex', function () {
210
+ describe('when successful (204)', function () {
211
+ beforeEach(function () {
212
+ _axios["default"]["delete"] = (0, _promises.resolvePromiseWith)({
213
+ status: 204,
214
+ data: undefined
215
+ });
216
+ });
217
+ test('returns an empty object with no error', function () {
218
+ expect.assertions(2);
219
+ return (0, _customIndexes.deleteCustomIndex)({
220
+ kappSlug: 'k',
221
+ formSlug: 'f',
222
+ indexName: 'My Index'
223
+ }).then(function (result) {
224
+ expect(result.error).toBeUndefined();
225
+ expect(result).toEqual({});
226
+ });
227
+ });
228
+ test('targets the named-index URL', function () {
229
+ expect.assertions(1);
230
+ return (0, _customIndexes.deleteCustomIndex)({
231
+ kappSlug: 'k',
232
+ formSlug: 'f',
233
+ indexName: 'My Index'
234
+ }).then(function () {
235
+ expect(_axios["default"]["delete"]).toHaveBeenCalledWith('app/api/v1/kapps/k/forms/f/indexes/My%20Index', expect.any(Object));
236
+ });
237
+ });
238
+ });
239
+ describe('when 404', function () {
240
+ beforeEach(function () {
241
+ _axios["default"]["delete"] = (0, _promises.rejectPromiseWith)({
242
+ response: {
243
+ status: 404,
244
+ statusText: 'Not Found',
245
+ headers: {
246
+ 'content-type': 'application/json'
247
+ },
248
+ data: {
249
+ error: 'No custom index with that name exists on this form.'
250
+ }
251
+ }
252
+ });
253
+ });
254
+ test('returns error with notFound flag', function () {
255
+ expect.assertions(2);
256
+ return (0, _customIndexes.deleteCustomIndex)({
257
+ kappSlug: 'k',
258
+ formSlug: 'f',
259
+ indexName: 'Missing'
260
+ }).then(function (_ref5) {
261
+ var error = _ref5.error;
262
+ expect(error.statusCode).toBe(404);
263
+ expect(error.notFound).toBe(true);
264
+ });
265
+ });
266
+ });
267
+ test('throws when required options are missing', function () {
268
+ expect(function () {
269
+ return (0, _customIndexes.deleteCustomIndex)({
270
+ kappSlug: 'k',
271
+ formSlug: 'f'
272
+ });
273
+ }).toThrow();
274
+ });
275
+ });
276
+ });
@@ -4,14 +4,24 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.updateOAuthClient = exports.fetchOAuthClients = exports.fetchOAuthClient = exports.deleteOAuthClient = exports.createOAuthClient = void 0;
7
+ exports.updateOAuthClient = exports.resetOAuthClientSecret = exports.fetchOAuthClients = exports.fetchOAuthClient = exports.deleteOAuthClient = exports.createOAuthClient = void 0;
8
8
  var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/esm/objectSpread2"));
9
9
  var _axios = _interopRequireDefault(require("axios"));
10
10
  var _helpers = require("../../helpers");
11
11
  var _http = require("../http");
12
12
  var buildEndpoint = function buildEndpoint(_ref) {
13
- var clientId = _ref.clientId;
14
- return clientId ? "".concat(_helpers.bundle.apiLocation(), "/oauthClients/").concat(encodeURIComponent(clientId)) : "".concat(_helpers.bundle.apiLocation(), "/oauthClients");
13
+ var clientId = _ref.clientId,
14
+ username = _ref.username,
15
+ me = _ref.me;
16
+ var base;
17
+ if (me) {
18
+ base = "".concat(_helpers.bundle.apiLocation(), "/me/oauthClients");
19
+ } else if (username) {
20
+ base = "".concat(_helpers.bundle.apiLocation(), "/users/").concat(encodeURIComponent(username), "/oauthClients");
21
+ } else {
22
+ base = "".concat(_helpers.bundle.apiLocation(), "/oauthClients");
23
+ }
24
+ return clientId ? "".concat(base, "/").concat(encodeURIComponent(clientId)) : base;
15
25
  };
16
26
  var fetchOAuthClients = exports.fetchOAuthClients = function fetchOAuthClients() {
17
27
  var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
@@ -35,7 +45,7 @@ var fetchOAuthClient = exports.fetchOAuthClient = function fetchOAuthClient() {
35
45
  headers: (0, _http.headerBuilder)(options)
36
46
  }).then(function (response) {
37
47
  return {
38
- client: response.data.client
48
+ client: response.data.oauthClient
39
49
  };
40
50
  })["catch"](_http.handleErrors);
41
51
  };
@@ -56,7 +66,7 @@ var updateOAuthClient = exports.updateOAuthClient = function updateOAuthClient()
56
66
  headers: (0, _http.headerBuilder)(options)
57
67
  }).then(function (response) {
58
68
  return {
59
- client: response.data.client
69
+ client: response.data.oauthClient
60
70
  };
61
71
  })["catch"](_http.handleErrors);
62
72
  };
@@ -64,7 +74,7 @@ var createOAuthClient = exports.createOAuthClient = function createOAuthClient()
64
74
  var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
65
75
  var client = options.client;
66
76
  if (!client) {
67
- throw new Error('updateOAuthClient failed! The option "client" is required.');
77
+ throw new Error('createOAuthClient failed! The option "client" is required.');
68
78
  }
69
79
 
70
80
  // Build URL and fetch the space.
@@ -73,7 +83,22 @@ var createOAuthClient = exports.createOAuthClient = function createOAuthClient()
73
83
  headers: (0, _http.headerBuilder)(options)
74
84
  }).then(function (response) {
75
85
  return {
76
- client: response.data.client
86
+ client: response.data.oauthClient
87
+ };
88
+ })["catch"](_http.handleErrors);
89
+ };
90
+ var resetOAuthClientSecret = exports.resetOAuthClientSecret = function resetOAuthClientSecret() {
91
+ var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
92
+ var clientId = options.clientId;
93
+ if (!clientId) {
94
+ throw new Error('resetOAuthClientSecret failed! The option "clientId" is required.');
95
+ }
96
+ return _axios["default"].post("".concat(buildEndpoint(options), "/secret"), null, {
97
+ params: (0, _http.paramBuilder)(options),
98
+ headers: (0, _http.headerBuilder)(options)
99
+ }).then(function (response) {
100
+ return {
101
+ client: response.data.oauthClient
77
102
  };
78
103
  })["catch"](_http.handleErrors);
79
104
  };
@@ -90,7 +115,7 @@ var deleteOAuthClient = exports.deleteOAuthClient = function deleteOAuthClient()
90
115
  headers: (0, _http.headerBuilder)(options)
91
116
  }).then(function (response) {
92
117
  return {
93
- client: response.data.client
118
+ client: response.data.oauthClient
94
119
  };
95
120
  })["catch"](_http.handleErrors);
96
121
  };
package/lib/apis/index.js CHANGED
@@ -156,6 +156,18 @@ Object.keys(_categories).forEach(function (key) {
156
156
  }
157
157
  });
158
158
  });
159
+ var _customIndexes = require("./core/customIndexes");
160
+ Object.keys(_customIndexes).forEach(function (key) {
161
+ if (key === "default" || key === "__esModule") return;
162
+ if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
163
+ if (key in exports && exports[key] === _customIndexes[key]) return;
164
+ Object.defineProperty(exports, key, {
165
+ enumerable: true,
166
+ get: function get() {
167
+ return _customIndexes[key];
168
+ }
169
+ });
170
+ });
159
171
  var _fileResources = require("./core/fileResources");
160
172
  Object.keys(_fileResources).forEach(function (key) {
161
173
  if (key === "default" || key === "__esModule") return;
@@ -0,0 +1,140 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault")["default"];
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.CustomIndexForm = void 0;
8
+ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/esm/toConsumableArray"));
9
+ var _apis = require("../../../apis");
10
+ var _Form = require("../../form/Form");
11
+ var _helpers = require("../../../helpers");
12
+ var PART_SEPARATOR = ':';
13
+ var PROPERTY_PREFIX = "property".concat(PART_SEPARATOR);
14
+ var VALUE_PREFIX = "value".concat(PART_SEPARATOR);
15
+ var encodePart = function encodePart(type, name) {
16
+ return "".concat(type).concat(PART_SEPARATOR).concat(name);
17
+ };
18
+ var decodePart = function decodePart(encoded) {
19
+ var idx = encoded.indexOf(PART_SEPARATOR);
20
+ return {
21
+ type: encoded.slice(0, idx),
22
+ name: encoded.slice(idx + 1)
23
+ };
24
+ };
25
+ var propertyOptions = _helpers.CUSTOM_INDEX_PROPERTIES.map(function (p) {
26
+ return {
27
+ label: "Property \u2014 ".concat(p),
28
+ value: "".concat(PROPERTY_PREFIX).concat(p)
29
+ };
30
+ });
31
+ var buildFieldOptions = function buildFieldOptions(fields) {
32
+ if (!fields) return [];
33
+ var seen = new Set();
34
+ return fields.map(function (f) {
35
+ return f.get('name');
36
+ }).filter(function (name) {
37
+ if (seen.has(name)) return false;
38
+ seen.add(name);
39
+ return true;
40
+ }).sort().map(function (name) {
41
+ return {
42
+ label: "Field \u2014 ".concat(name),
43
+ value: "".concat(VALUE_PREFIX).concat(name)
44
+ };
45
+ }).toArray();
46
+ };
47
+ var dataSources = function dataSources(_ref) {
48
+ var kappSlug = _ref.kappSlug,
49
+ formSlug = _ref.formSlug;
50
+ return {
51
+ form: {
52
+ fn: _apis.fetchForm,
53
+ params: [{
54
+ kappSlug: kappSlug,
55
+ formSlug: formSlug,
56
+ include: 'fields'
57
+ }],
58
+ transform: function transform(result) {
59
+ return result.form;
60
+ }
61
+ },
62
+ fields: {
63
+ fn: function fn(form) {
64
+ return form.get('fields');
65
+ },
66
+ params: function params(_ref2) {
67
+ var form = _ref2.form;
68
+ return form && [form];
69
+ }
70
+ }
71
+ };
72
+ };
73
+ var handleSubmit = function handleSubmit(_ref3) {
74
+ var kappSlug = _ref3.kappSlug,
75
+ formSlug = _ref3.formSlug;
76
+ return function (values) {
77
+ var parts = values.get('parts').toJS().map(decodePart);
78
+ return (0, _apis.createCustomIndex)({
79
+ kappSlug: kappSlug,
80
+ formSlug: formSlug,
81
+ index: {
82
+ name: values.get('name'),
83
+ unique: values.get('unique'),
84
+ parts: parts
85
+ }
86
+ }).then(function (_ref4) {
87
+ var index = _ref4.index,
88
+ error = _ref4.error;
89
+ if (error) {
90
+ // Surface server-supplied message (400 validation, 422 cap reached,
91
+ // 502 Postgres rejection — e.g. unique on duplicate data).
92
+ throw error.message || 'There was an error creating the custom index.';
93
+ }
94
+ return index;
95
+ });
96
+ };
97
+ };
98
+ var fields = function fields() {
99
+ return function () {
100
+ return [{
101
+ name: 'name',
102
+ label: 'Name',
103
+ type: 'text',
104
+ required: true,
105
+ pattern: /^[A-Za-z0-9 _-]{1,64}$/,
106
+ patternMessage: 'Name may only contain letters, numbers, spaces, underscores, and hyphens (up to 64 characters).',
107
+ initialValue: ''
108
+ }, {
109
+ name: 'unique',
110
+ label: 'Unique',
111
+ type: 'checkbox',
112
+ helpText: 'When checked, prevents subsequent submissions from duplicating the indexed values within this form.',
113
+ initialValue: false
114
+ }, {
115
+ name: 'parts',
116
+ label: 'Parts',
117
+ type: 'select-multi',
118
+ required: true,
119
+ helpText: 'Order matters — it determines the leading-column order of the index. Up to 4 parts.',
120
+ options: function options(_ref5) {
121
+ var fields = _ref5.fields;
122
+ return [].concat((0, _toConsumableArray2["default"])(buildFieldOptions(fields)), (0, _toConsumableArray2["default"])(propertyOptions));
123
+ },
124
+ constraint: function constraint(_ref6) {
125
+ var values = _ref6.values;
126
+ var parts = values.get('parts');
127
+ return parts && parts.size >= 1 && parts.size <= 4;
128
+ },
129
+ constraintMessage: 'Select between 1 and 4 parts.',
130
+ initialValue: []
131
+ }];
132
+ };
133
+ };
134
+ var CustomIndexForm = exports.CustomIndexForm = (0, _Form.generateForm)({
135
+ formOptions: ['kappSlug', 'formSlug'],
136
+ dataSources: dataSources,
137
+ fields: fields,
138
+ handleSubmit: handleSubmit
139
+ });
140
+ CustomIndexForm.displayName = 'CustomIndexForm';
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault")["default"];
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.CustomIndexTable = void 0;
8
+ var _react = _interopRequireDefault(require("react"));
9
+ var _Table = require("../../table/Table");
10
+ var _apis = require("../../../apis");
11
+ var _helpers = require("../../../helpers");
12
+ var clientSide = (0, _helpers.defineFilter)(true).startsWith('name', 'name').equals('status', 'status').equals('unique', 'unique').end();
13
+ var BooleanYesNoCell = function BooleanYesNoCell(_ref) {
14
+ var value = _ref.value;
15
+ return /*#__PURE__*/_react["default"].createElement("td", null, value ? 'Yes' : 'No');
16
+ };
17
+ var formatPart = function formatPart(part) {
18
+ var type = part.get('type');
19
+ var name = part.get('name');
20
+ if (name == null) {
21
+ return "".concat(type, ":\u27E8deleted field\u27E9");
22
+ }
23
+ return "".concat(type, ":").concat(name);
24
+ };
25
+ var PartsCell = function PartsCell(_ref2) {
26
+ var value = _ref2.value;
27
+ if (!value || value.size === 0) {
28
+ return /*#__PURE__*/_react["default"].createElement("td", null);
29
+ }
30
+ var hasOrphan = value.some(function (p) {
31
+ return p.get('name') == null;
32
+ });
33
+ return /*#__PURE__*/_react["default"].createElement("td", {
34
+ title: hasOrphan ? 'One or more referenced fields have been deleted' : undefined
35
+ }, value.map(formatPart).join(', '));
36
+ };
37
+ var dataSource = function dataSource(_ref3) {
38
+ var kappSlug = _ref3.kappSlug,
39
+ formSlug = _ref3.formSlug;
40
+ return {
41
+ fn: _apis.fetchCustomIndexes,
42
+ clientSide: clientSide,
43
+ params: function params() {
44
+ return [{
45
+ kappSlug: kappSlug,
46
+ formSlug: formSlug
47
+ }];
48
+ },
49
+ transform: function transform(result) {
50
+ return {
51
+ data: result.indexes
52
+ };
53
+ }
54
+ };
55
+ };
56
+ var columns = [{
57
+ value: 'name',
58
+ title: 'Name',
59
+ toggleable: false,
60
+ columnOrder: 'first'
61
+ }, {
62
+ value: 'status',
63
+ title: 'Status',
64
+ toggleable: true
65
+ }, {
66
+ value: 'unique',
67
+ title: 'Unique',
68
+ toggleable: true,
69
+ components: {
70
+ BodyCell: BooleanYesNoCell
71
+ }
72
+ }, {
73
+ value: 'parts',
74
+ title: 'Parts',
75
+ toggleable: true,
76
+ components: {
77
+ BodyCell: PartsCell
78
+ }
79
+ }, {
80
+ value: 'errorMessage',
81
+ title: 'Error',
82
+ toggleable: true
83
+ }, {
84
+ value: 'createdAt',
85
+ title: 'Created At',
86
+ toggleable: true
87
+ }, {
88
+ value: 'createdBy',
89
+ title: 'Created By',
90
+ toggleable: true
91
+ }];
92
+ var CustomIndexTable = exports.CustomIndexTable = (0, _Table.generateTable)({
93
+ tableOptions: ['kappSlug', 'formSlug'],
94
+ sortable: false,
95
+ columns: columns,
96
+ dataSource: dataSource
97
+ });
98
+ CustomIndexTable.displayName = 'CustomIndexTable';