@mapcreator/api 0.0.0-co-edit.9 → 0.0.0-json-object.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.
- package/LICENSE +29 -29
- package/README.md +86 -86
- package/cjs/api/apiCommon.d.ts +1 -3
- package/cjs/api/apiCommon.d.ts.map +1 -1
- package/cjs/api/apiCommon.js +13 -6
- package/cjs/api/apiCommon.js.map +1 -1
- package/cjs/api/job.d.ts +13 -50
- package/cjs/api/job.d.ts.map +1 -1
- package/cjs/api/job.js +4 -42
- package/cjs/api/job.js.map +1 -1
- package/cjs/api/jobRevision.d.ts +4 -1
- package/cjs/api/jobRevision.d.ts.map +1 -1
- package/cjs/api/jobRevision.js +38 -1
- package/cjs/api/jobRevision.js.map +1 -1
- package/cjs/api/organisation.d.ts +2 -2
- package/cjs/api/organisation.d.ts.map +1 -1
- package/cjs/api/organisation.js +3 -2
- package/cjs/api/organisation.js.map +1 -1
- package/cjs/api/resources.d.ts +1 -23
- package/cjs/api/resources.d.ts.map +1 -1
- package/cjs/api/resources.js +0 -2
- package/cjs/api/resources.js.map +1 -1
- package/cjs/api/user.d.ts +18 -5
- package/cjs/api/user.d.ts.map +1 -1
- package/cjs/api/user.js +5 -9
- package/cjs/api/user.js.map +1 -1
- package/esm/api/apiCommon.d.ts +1 -3
- package/esm/api/apiCommon.d.ts.map +1 -1
- package/esm/api/apiCommon.js +13 -6
- package/esm/api/apiCommon.js.map +1 -1
- package/esm/api/job.d.ts +13 -50
- package/esm/api/job.d.ts.map +1 -1
- package/esm/api/job.js +4 -33
- package/esm/api/job.js.map +1 -1
- package/esm/api/jobRevision.d.ts +4 -1
- package/esm/api/jobRevision.d.ts.map +1 -1
- package/esm/api/jobRevision.js +36 -1
- package/esm/api/jobRevision.js.map +1 -1
- package/esm/api/organisation.d.ts +2 -2
- package/esm/api/organisation.d.ts.map +1 -1
- package/esm/api/organisation.js +3 -2
- package/esm/api/organisation.js.map +1 -1
- package/esm/api/resources.d.ts +1 -23
- package/esm/api/resources.d.ts.map +1 -1
- package/esm/api/resources.js +0 -2
- package/esm/api/resources.js.map +1 -1
- package/esm/api/user.d.ts +18 -5
- package/esm/api/user.d.ts.map +1 -1
- package/esm/api/user.js +4 -7
- package/esm/api/user.js.map +1 -1
- package/package.json +81 -81
- package/src/README.md +126 -126
- package/src/api/apiCommon.ts +16 -23
- package/src/api/job.ts +18 -87
- package/src/api/jobRevision.ts +51 -1
- package/src/api/organisation.ts +6 -6
- package/src/api/resources.ts +1 -32
- package/src/api/user.ts +27 -21
package/src/README.md
CHANGED
|
@@ -1,126 +1,126 @@
|
|
|
1
|
-
### Used type system
|
|
2
|
-
|
|
3
|
-
We use type declarations for both the data coming over the wire and the data used by the application. In general, these types differ only in the presence of additional fields in the data arriving over the network (like `created_at`), and used naming convention. Data over the network uses the so-called snake case.
|
|
4
|
-
|
|
5
|
-
All in all, we can use TypeScript's native mechanisms to convert one type to another and fully define just one type:
|
|
6
|
-
|
|
7
|
-
```typescript
|
|
8
|
-
import type { CamelCasedProperties } from 'type-fest';
|
|
9
|
-
|
|
10
|
-
type ApiType =
|
|
11
|
-
| ({
|
|
12
|
-
data: {
|
|
13
|
-
prop: unknown;
|
|
14
|
-
} & ApiCommonData;
|
|
15
|
-
} & Omit<ApiSuccess, 'data'>)
|
|
16
|
-
| ApiError;
|
|
17
|
-
|
|
18
|
-
type AppType = CamelCasedProperties<Omit<Exclude<ApiType, ApiError>['data'], keyof ApiCommonData>>;
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
or in reverse order:
|
|
22
|
-
|
|
23
|
-
```typescript
|
|
24
|
-
import type { SnakeCasedProperties } from 'type-fest';
|
|
25
|
-
|
|
26
|
-
type AppType = {
|
|
27
|
-
prop: unknown;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
type ApiType =
|
|
31
|
-
| ({
|
|
32
|
-
data: SnakeCasedProperties<AppType> & ApiCommonData;
|
|
33
|
-
} & Omit<ApiSuccess, 'data'>)
|
|
34
|
-
| ApiError;
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
But the decision was made not to do this, since it may be more difficult for the developer to make the conversion in their head than to see it in front of their eyes.
|
|
38
|
-
|
|
39
|
-
### Using a `request()`
|
|
40
|
-
|
|
41
|
-
The function has the following signature:
|
|
42
|
-
|
|
43
|
-
```typescript
|
|
44
|
-
async function request<I extends ApiCommon, O extends Record<string, unknown> | string>(
|
|
45
|
-
path: string,
|
|
46
|
-
body?: XMLHttpRequestBodyInit | Record<string | number, unknown> | null,
|
|
47
|
-
extraHeaders?: Record<string, string> | null,
|
|
48
|
-
extraOptions?: ExtraOptions<I, O>,
|
|
49
|
-
): Promise<O | O[]> { /* ... */ }
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
Let's take it step by step.
|
|
53
|
-
|
|
54
|
-
`I extends ApiCommon` - represents the type of data we receive over the network.
|
|
55
|
-
|
|
56
|
-
`O extends Record<string, unknown> | string` - represents the data type that will be used in the application.
|
|
57
|
-
|
|
58
|
-
Ideally you should describe and convey both types. This will help to check the data types in the arguments passed.
|
|
59
|
-
See current data types for an example.
|
|
60
|
-
|
|
61
|
-
`path: string` - the path to the resource, must include the API version, but must not include the schema or authority.
|
|
62
|
-
Example: `/v1/jobs/12345`
|
|
63
|
-
|
|
64
|
-
`body?: XMLHttpRequestBodyInit | Record<string | number, unknown> | null` - any meaningful body type. In general,
|
|
65
|
-
the presence of an JSON object is assumed (or the absence of one for methods that only request data), but you can
|
|
66
|
-
also pass `Blob`, `FormData`, `URLSearchParams` or just `ArrayBuffer`. The required content type will be added to
|
|
67
|
-
the headers automatically.
|
|
68
|
-
|
|
69
|
-
`extraHeaders?: Record<string, string> | null` - the object with additional headers.
|
|
70
|
-
|
|
71
|
-
`extraOptions?: ExtraOptions<I, O>` - where `ExtraOptions<I, O>` is defined like this:
|
|
72
|
-
|
|
73
|
-
```typescript
|
|
74
|
-
interface ExtraOptions<I extends ApiCommon, O extends Record<string, unknown> | string> {
|
|
75
|
-
method?: 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
|
76
|
-
revivers?: O extends Record<string, unknown> ? Revivers<I, O> : never;
|
|
77
|
-
sendNull?: boolean;
|
|
78
|
-
withMeta?: boolean;
|
|
79
|
-
}
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
Most fields are self-explanatory.
|
|
83
|
-
|
|
84
|
-
`sendNull` can be used if you really want to pass `null` as body content.
|
|
85
|
-
|
|
86
|
-
`revivers` is used to specify an object that can modify the behavior of the internal handler of data coming over
|
|
87
|
-
the network. Let's take a closer look at this moment.
|
|
88
|
-
|
|
89
|
-
#### Revivers
|
|
90
|
-
|
|
91
|
-
By default, the `request()` function does the following things with data coming over the network:
|
|
92
|
-
|
|
93
|
-
- It removes `created_at`, `updated_at`, `deleted_at` fields from the output objects.
|
|
94
|
-
- It preserves all the remaining fields but converts their names into camelCase.
|
|
95
|
-
|
|
96
|
-
When passing an object with revivers you can a couple of things:
|
|
97
|
-
|
|
98
|
-
- You can list the fields that you want **to exclude** from the result object. To do this, the field must be assigned an
|
|
99
|
-
`undefined` value.
|
|
100
|
-
- You can **add** new fields or **modify** the type of existing ones. To do this, you need to pass a function as a field
|
|
101
|
-
value, which will receive the original object as input.
|
|
102
|
-
|
|
103
|
-
Example:
|
|
104
|
-
|
|
105
|
-
```typescript
|
|
106
|
-
const jobRevivers: Revivers<ApiJob, Job> = {
|
|
107
|
-
user_id: undefined,
|
|
108
|
-
description: undefined,
|
|
109
|
-
share_token: undefined,
|
|
110
|
-
autosave_preview_path: undefined,
|
|
111
|
-
job_folder_id: undefined,
|
|
112
|
-
|
|
113
|
-
jobTypeId: () => 9,
|
|
114
|
-
createdAt: (data: ApiJobData) => data.created_at as string,
|
|
115
|
-
previewPath: (data: ApiJobData) => data.autosave_preview_path ?? undefined,
|
|
116
|
-
};
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
`user_id`, `description`, `share_token`, `autosave_preview_path`, `job_folder_id` fields will be excluded from the
|
|
120
|
-
result object.
|
|
121
|
-
|
|
122
|
-
`jobTypeId` will be always **9**.
|
|
123
|
-
|
|
124
|
-
`createdAt` will be returned (please note that that field is excluded by default)
|
|
125
|
-
|
|
126
|
-
`previewPath` - some actions will be performed with the source data.
|
|
1
|
+
### Used type system
|
|
2
|
+
|
|
3
|
+
We use type declarations for both the data coming over the wire and the data used by the application. In general, these types differ only in the presence of additional fields in the data arriving over the network (like `created_at`), and used naming convention. Data over the network uses the so-called snake case.
|
|
4
|
+
|
|
5
|
+
All in all, we can use TypeScript's native mechanisms to convert one type to another and fully define just one type:
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import type { CamelCasedProperties } from 'type-fest';
|
|
9
|
+
|
|
10
|
+
type ApiType =
|
|
11
|
+
| ({
|
|
12
|
+
data: {
|
|
13
|
+
prop: unknown;
|
|
14
|
+
} & ApiCommonData;
|
|
15
|
+
} & Omit<ApiSuccess, 'data'>)
|
|
16
|
+
| ApiError;
|
|
17
|
+
|
|
18
|
+
type AppType = CamelCasedProperties<Omit<Exclude<ApiType, ApiError>['data'], keyof ApiCommonData>>;
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
or in reverse order:
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import type { SnakeCasedProperties } from 'type-fest';
|
|
25
|
+
|
|
26
|
+
type AppType = {
|
|
27
|
+
prop: unknown;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
type ApiType =
|
|
31
|
+
| ({
|
|
32
|
+
data: SnakeCasedProperties<AppType> & ApiCommonData;
|
|
33
|
+
} & Omit<ApiSuccess, 'data'>)
|
|
34
|
+
| ApiError;
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
But the decision was made not to do this, since it may be more difficult for the developer to make the conversion in their head than to see it in front of their eyes.
|
|
38
|
+
|
|
39
|
+
### Using a `request()`
|
|
40
|
+
|
|
41
|
+
The function has the following signature:
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
async function request<I extends ApiCommon, O extends Record<string, unknown> | string>(
|
|
45
|
+
path: string,
|
|
46
|
+
body?: XMLHttpRequestBodyInit | Record<string | number, unknown> | null,
|
|
47
|
+
extraHeaders?: Record<string, string> | null,
|
|
48
|
+
extraOptions?: ExtraOptions<I, O>,
|
|
49
|
+
): Promise<O | O[]> { /* ... */ }
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Let's take it step by step.
|
|
53
|
+
|
|
54
|
+
`I extends ApiCommon` - represents the type of data we receive over the network.
|
|
55
|
+
|
|
56
|
+
`O extends Record<string, unknown> | string` - represents the data type that will be used in the application.
|
|
57
|
+
|
|
58
|
+
Ideally you should describe and convey both types. This will help to check the data types in the arguments passed.
|
|
59
|
+
See current data types for an example.
|
|
60
|
+
|
|
61
|
+
`path: string` - the path to the resource, must include the API version, but must not include the schema or authority.
|
|
62
|
+
Example: `/v1/jobs/12345`
|
|
63
|
+
|
|
64
|
+
`body?: XMLHttpRequestBodyInit | Record<string | number, unknown> | null` - any meaningful body type. In general,
|
|
65
|
+
the presence of an JSON object is assumed (or the absence of one for methods that only request data), but you can
|
|
66
|
+
also pass `Blob`, `FormData`, `URLSearchParams` or just `ArrayBuffer`. The required content type will be added to
|
|
67
|
+
the headers automatically.
|
|
68
|
+
|
|
69
|
+
`extraHeaders?: Record<string, string> | null` - the object with additional headers.
|
|
70
|
+
|
|
71
|
+
`extraOptions?: ExtraOptions<I, O>` - where `ExtraOptions<I, O>` is defined like this:
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
interface ExtraOptions<I extends ApiCommon, O extends Record<string, unknown> | string> {
|
|
75
|
+
method?: 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
|
76
|
+
revivers?: O extends Record<string, unknown> ? Revivers<I, O> : never;
|
|
77
|
+
sendNull?: boolean;
|
|
78
|
+
withMeta?: boolean;
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Most fields are self-explanatory.
|
|
83
|
+
|
|
84
|
+
`sendNull` can be used if you really want to pass `null` as body content.
|
|
85
|
+
|
|
86
|
+
`revivers` is used to specify an object that can modify the behavior of the internal handler of data coming over
|
|
87
|
+
the network. Let's take a closer look at this moment.
|
|
88
|
+
|
|
89
|
+
#### Revivers
|
|
90
|
+
|
|
91
|
+
By default, the `request()` function does the following things with data coming over the network:
|
|
92
|
+
|
|
93
|
+
- It removes `created_at`, `updated_at`, `deleted_at` fields from the output objects.
|
|
94
|
+
- It preserves all the remaining fields but converts their names into camelCase.
|
|
95
|
+
|
|
96
|
+
When passing an object with revivers you can a couple of things:
|
|
97
|
+
|
|
98
|
+
- You can list the fields that you want **to exclude** from the result object. To do this, the field must be assigned an
|
|
99
|
+
`undefined` value.
|
|
100
|
+
- You can **add** new fields or **modify** the type of existing ones. To do this, you need to pass a function as a field
|
|
101
|
+
value, which will receive the original object as input.
|
|
102
|
+
|
|
103
|
+
Example:
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
const jobRevivers: Revivers<ApiJob, Job> = {
|
|
107
|
+
user_id: undefined,
|
|
108
|
+
description: undefined,
|
|
109
|
+
share_token: undefined,
|
|
110
|
+
autosave_preview_path: undefined,
|
|
111
|
+
job_folder_id: undefined,
|
|
112
|
+
|
|
113
|
+
jobTypeId: () => 9,
|
|
114
|
+
createdAt: (data: ApiJobData) => data.created_at as string,
|
|
115
|
+
previewPath: (data: ApiJobData) => data.autosave_preview_path ?? undefined,
|
|
116
|
+
};
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
`user_id`, `description`, `share_token`, `autosave_preview_path`, `job_folder_id` fields will be excluded from the
|
|
120
|
+
result object.
|
|
121
|
+
|
|
122
|
+
`jobTypeId` will be always **9**.
|
|
123
|
+
|
|
124
|
+
`createdAt` will be returned (please note that that field is excluded by default)
|
|
125
|
+
|
|
126
|
+
`previewPath` - some actions will be performed with the source data.
|
package/src/api/apiCommon.ts
CHANGED
|
@@ -9,20 +9,6 @@ import {
|
|
|
9
9
|
request,
|
|
10
10
|
} from '../utils.js';
|
|
11
11
|
|
|
12
|
-
export type DashboardSortType =
|
|
13
|
-
| 'created'
|
|
14
|
-
| '-created'
|
|
15
|
-
| 'updated'
|
|
16
|
-
| '-updated'
|
|
17
|
-
| 'last_opened'
|
|
18
|
-
| '-last_opened'
|
|
19
|
-
| 'last_saved'
|
|
20
|
-
| '-last_saved'
|
|
21
|
-
| 'name'
|
|
22
|
-
| '-name';
|
|
23
|
-
|
|
24
|
-
export type DashboardFilterType = 'all' | 'starred' | 'private';
|
|
25
|
-
|
|
26
12
|
export interface JobSearchResult {
|
|
27
13
|
pageCount: number;
|
|
28
14
|
data: Job[];
|
|
@@ -30,18 +16,25 @@ export interface JobSearchResult {
|
|
|
30
16
|
|
|
31
17
|
export async function listJobs(
|
|
32
18
|
pathname: string,
|
|
33
|
-
|
|
34
|
-
sort: DashboardSortType,
|
|
35
|
-
filter: DashboardFilterType,
|
|
19
|
+
title: string,
|
|
36
20
|
page: number,
|
|
37
|
-
|
|
21
|
+
searchOptions?: Record<string, unknown>,
|
|
38
22
|
): Promise<JobSearchResult> {
|
|
23
|
+
const defaultSearchOptions = {
|
|
24
|
+
sort: '-updated',
|
|
25
|
+
only_downloaded: false,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const search = { ...defaultSearchOptions, ...searchOptions };
|
|
29
|
+
|
|
39
30
|
const query = getSearchParams({
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
31
|
+
only_with_revisions: true,
|
|
32
|
+
search: {
|
|
33
|
+
job_type_id: ['9', '6'],
|
|
34
|
+
converted_job_id: '=:',
|
|
35
|
+
...(title.length > 0 && { title: `~:${title}` }),
|
|
36
|
+
},
|
|
37
|
+
...search,
|
|
45
38
|
});
|
|
46
39
|
|
|
47
40
|
const path = `${pathname}?${query}`;
|
package/src/api/job.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ApiJobShare, JobShare, JobShareVisibility } from './jobShare.js';
|
|
2
|
-
import { type
|
|
2
|
+
import { type JobSearchResult, listJobs } from './apiCommon.js';
|
|
3
3
|
import {
|
|
4
4
|
type ApiCommon,
|
|
5
5
|
type ApiCommonData,
|
|
@@ -14,54 +14,40 @@ import {
|
|
|
14
14
|
export type Job = {
|
|
15
15
|
id: number;
|
|
16
16
|
jobTypeId: number;
|
|
17
|
-
title: string;
|
|
18
|
-
autosavePreviewPath: string | null;
|
|
19
|
-
previewPath: string | undefined;
|
|
20
17
|
userId: number;
|
|
21
|
-
|
|
22
|
-
orgId: number;
|
|
23
|
-
orgName: string;
|
|
24
|
-
jobOpenUserName: string | null;
|
|
18
|
+
title: string;
|
|
25
19
|
jobFolderId: number | null;
|
|
26
20
|
jobFolderName: string | null;
|
|
27
21
|
star: boolean;
|
|
28
|
-
private: boolean;
|
|
29
|
-
convertedJobId: number | null;
|
|
30
|
-
lastOpened: string | null;
|
|
31
|
-
downloadedAt: string | null;
|
|
32
|
-
lastSavedAt: string;
|
|
33
|
-
latestRevision: number;
|
|
34
22
|
createdAt: string;
|
|
35
|
-
|
|
23
|
+
previewPath: string | undefined;
|
|
24
|
+
convertedJobId: number | null;
|
|
25
|
+
|
|
26
|
+
userEmail: string | undefined; // ?
|
|
27
|
+
orgName: string | undefined; // ?
|
|
36
28
|
};
|
|
37
29
|
|
|
38
30
|
export type ApiJob = {
|
|
39
31
|
data: {
|
|
40
32
|
id: number; // The job id (sortable)
|
|
41
33
|
job_type_id: number; // The id of the job type (searchable)
|
|
34
|
+
user_id: number; // The user id (searchable)
|
|
42
35
|
title: string; // The title of the job (searchable, sortable)
|
|
36
|
+
description: string | null; // The description of the job (searchable, sortable)
|
|
37
|
+
share_token: string | null; // The token used for sharing this job
|
|
43
38
|
autosave_preview_path: string | null; // The preview path of the Job
|
|
44
|
-
preview_path: string;
|
|
45
|
-
user_id: number; // The user id (searchable)
|
|
46
|
-
user_name: string | null;
|
|
47
|
-
org_id: number;
|
|
48
|
-
org_name: string;
|
|
49
|
-
job_open_user_name: string | null;
|
|
50
39
|
job_folder_id: number | null; // TODO: not present in API specification!
|
|
51
|
-
job_folder_name
|
|
40
|
+
job_folder_name?: string | null; // TODO: not present in API specification!
|
|
52
41
|
star: boolean; // TODO: not present in API specification!
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
last_opened: string | null;
|
|
56
|
-
downloaded_at: string | null;
|
|
57
|
-
last_saved_at: string;
|
|
58
|
-
latest_revision: number;
|
|
59
|
-
} & Omit<ApiCommonData, 'deleted_at'>;
|
|
42
|
+
converted_job_id?: number | null;
|
|
43
|
+
} & ApiCommonData;
|
|
60
44
|
} & Omit<ApiSuccess, 'data'> | ApiError;
|
|
61
45
|
|
|
62
46
|
export type ApiJobData = Flatten<Exclude<ApiJob, ApiError>['data']>;
|
|
63
47
|
|
|
64
48
|
export const jobRevivers: Revivers<ApiJob, Job> = {
|
|
49
|
+
description: undefined,
|
|
50
|
+
share_token: undefined,
|
|
65
51
|
autosave_preview_path: undefined,
|
|
66
52
|
|
|
67
53
|
jobFolderName: (data: ApiJobData) => data.job_folder_name ?? null,
|
|
@@ -94,12 +80,6 @@ export async function deleteJob(jobId: number): Promise<Record<string, never>> {
|
|
|
94
80
|
return request<ApiCommon, Record<string, never>>(path, null, null, { method: 'DELETE' });
|
|
95
81
|
}
|
|
96
82
|
|
|
97
|
-
export async function restoreJob(jobId: number): Promise<Record<string, never>> {
|
|
98
|
-
const path = `/v1/jobs/${jobId}`;
|
|
99
|
-
|
|
100
|
-
return request<ApiCommon, Record<string, never>>(path, null, null, { method: 'PUT' });
|
|
101
|
-
}
|
|
102
|
-
|
|
103
83
|
export async function updateJob(jobId: number, newTitle: string): Promise<Record<string, never>> {
|
|
104
84
|
const path = `/v1/jobs/${jobId}`;
|
|
105
85
|
const body = { title: newTitle };
|
|
@@ -121,13 +101,6 @@ export async function starJob(jobId: number, star: boolean): Promise<Record<stri
|
|
|
121
101
|
return request<ApiCommon, Record<string, never>>(path, body, null, { method: 'PATCH' });
|
|
122
102
|
}
|
|
123
103
|
|
|
124
|
-
export async function privateJob(jobId: number, privateValue: boolean): Promise<Record<string, never>> {
|
|
125
|
-
const path = `/v1/jobs/${jobId}`;
|
|
126
|
-
const body = { private: privateValue };
|
|
127
|
-
|
|
128
|
-
return request<ApiCommon, Record<string, never>>(path, body, null, { method: 'PATCH' });
|
|
129
|
-
}
|
|
130
|
-
|
|
131
104
|
export async function resetConvertedJob(jobId: number): Promise<Record<string, never>> {
|
|
132
105
|
const path = `/v1/jobs/${jobId}/reset-converted`;
|
|
133
106
|
|
|
@@ -158,51 +131,9 @@ export async function uploadJobPreview(
|
|
|
158
131
|
}
|
|
159
132
|
|
|
160
133
|
export async function listFeaturedJobs(
|
|
161
|
-
|
|
162
|
-
sort: DashboardSortType,
|
|
134
|
+
title: string,
|
|
163
135
|
page: number,
|
|
136
|
+
options?: Record<string, unknown>,
|
|
164
137
|
): Promise<JobSearchResult> {
|
|
165
|
-
return listJobs(`/v1/jobs/featured`,
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
export type JobCoEditEvent = {
|
|
169
|
-
jobId: number;
|
|
170
|
-
userName: string;
|
|
171
|
-
status: 'open' | 'close';
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
export type JobTakeoverEvent = {
|
|
175
|
-
userId: number;
|
|
176
|
-
userName: string;
|
|
177
|
-
requestedAt: string;
|
|
178
|
-
status: 'pending' | 'approved' | 'denied' | 'cancelled';
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
export async function openJob(jobId: number): Promise<Record<string, never>> {
|
|
182
|
-
return request<ApiCommon, Record<string, never>>(`/v1/jobs/${jobId}/open`, null, null, { method: 'POST' });
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
export async function heartbeat(jobId: number): Promise<Record<string, never>> {
|
|
186
|
-
// TODO handle disconnections. Throw the right error so we can show a modal in the tool when the connection is down
|
|
187
|
-
return request<ApiCommon, Record<string, never>>(`/v1/jobs/${jobId}/heartbeat`, null, null, { method: 'POST' });
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
export async function requestTakeover(jobId: number): Promise<Record<string, never>> {
|
|
191
|
-
return request<ApiCommon, Record<string, never>>(`/v1/jobs/${jobId}/takeover/request`, null, null, { method: 'POST' });
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
export async function approveTakeover(jobId: number, userId: number): Promise<Record<string, never>> {
|
|
195
|
-
return request<ApiCommon, Record<string, never>>(`/v1/jobs/${jobId}/takeover/approve`, { user_id: userId }, null, { method: 'POST' });
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
export async function denyTakeover(jobId: number, userId: number): Promise<Record<string, never>> {
|
|
199
|
-
return request<ApiCommon, Record<string, never>>(`/v1/jobs/${jobId}/takeover/deny`, { user_id: userId }, null, { method: 'POST' });
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
export async function cancelTakeover(jobId: number): Promise<Record<string, never>> {
|
|
203
|
-
return request<ApiCommon, Record<string, never>>(`/v1/jobs/${jobId}/takeover/cancel`, null, null, { method: 'POST' });
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
export async function closeJob(jobId: number): Promise<Record<string, never>> {
|
|
207
|
-
return request<ApiCommon, Record<string, never>>(`/v1/jobs/${jobId}/close`, null, null, { method: 'POST' });
|
|
138
|
+
return listJobs(`/v1/jobs/featured`, title, page, options);
|
|
208
139
|
}
|
package/src/api/jobRevision.ts
CHANGED
|
@@ -82,7 +82,7 @@ export async function createJobRevision(
|
|
|
82
82
|
const body = {
|
|
83
83
|
language_code: languageCode,
|
|
84
84
|
mapstyle_set_id: mapstyleSetId,
|
|
85
|
-
object:
|
|
85
|
+
object: jobObject,
|
|
86
86
|
output,
|
|
87
87
|
layers,
|
|
88
88
|
...skipValidation && { skip_validation: skipValidation },
|
|
@@ -354,3 +354,53 @@ export async function getJobRevisionOutputForBackend(
|
|
|
354
354
|
|
|
355
355
|
return fetchOutput(jobId);
|
|
356
356
|
}
|
|
357
|
+
|
|
358
|
+
export async function startJobRevisionSSR(
|
|
359
|
+
jobId: number,
|
|
360
|
+
revision: number | typeof lastJobRevision = lastJobRevision,
|
|
361
|
+
): Promise<string> {
|
|
362
|
+
const pathname = `/v1/jobs/${jobId}/revisions/${revision}/build/ssr`;
|
|
363
|
+
const path = `${pathname}?${deletedNoneParam}`;
|
|
364
|
+
|
|
365
|
+
return request<ApiCommon, string>(path, null, null, { method: 'POST' });
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
export async function getJobRevisionOutputForSSR(
|
|
369
|
+
id: number, // jobRevisionId
|
|
370
|
+
echo: Echo<'reverb'>,
|
|
371
|
+
signal?: AbortSignal,
|
|
372
|
+
onProgress?: (percent: number) => void,
|
|
373
|
+
): Promise<string> {
|
|
374
|
+
signal?.throwIfAborted();
|
|
375
|
+
|
|
376
|
+
return new Promise((resolve, reject) => {
|
|
377
|
+
const channel = `ssr.${id}`;
|
|
378
|
+
|
|
379
|
+
const onAbort = (): void => {
|
|
380
|
+
echo.leave(channel);
|
|
381
|
+
reject(signal?.reason);
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
const cleanup = (): void => {
|
|
385
|
+
echo.leave(channel);
|
|
386
|
+
signal?.removeEventListener('abort', onAbort);
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
const handler = (event: { jobRevisionId: number; status: string; url?: string }): void => {
|
|
390
|
+
if (event.status === 'RUNNING') {
|
|
391
|
+
onProgress?.(0);
|
|
392
|
+
} else if (event.status === 'SUCCEEDED' && event.url) {
|
|
393
|
+
cleanup();
|
|
394
|
+
resolve(event.url);
|
|
395
|
+
} else if (event.status === 'FAILED' || event.status === 'SUCCEEDED' && !event.url) {
|
|
396
|
+
cleanup();
|
|
397
|
+
reject(
|
|
398
|
+
new APIError({ success: false, error: { type: 'API Error', message: event.status } }),
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
404
|
+
echo.private(channel).listen('.ServerSideRenderingEvent', handler);
|
|
405
|
+
});
|
|
406
|
+
}
|
package/src/api/organisation.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ApiJobShareArray, JobShare } from './jobShare.js';
|
|
2
|
-
import { type
|
|
2
|
+
import { type JobSearchResult, listJobs } from './apiCommon.js';
|
|
3
3
|
import {
|
|
4
4
|
type ApiCommonData,
|
|
5
5
|
type ApiError,
|
|
@@ -74,13 +74,13 @@ export async function getOrganisation(
|
|
|
74
74
|
|
|
75
75
|
export async function listOrganisationJobs(
|
|
76
76
|
organisationId: number | typeof myOrganisations,
|
|
77
|
-
|
|
78
|
-
sort: DashboardSortType,
|
|
79
|
-
filter: DashboardFilterType,
|
|
77
|
+
title: string,
|
|
80
78
|
page: number,
|
|
81
|
-
|
|
79
|
+
options?: Record<string, unknown>,
|
|
82
80
|
): Promise<JobSearchResult> {
|
|
83
|
-
|
|
81
|
+
const search = { ...options };
|
|
82
|
+
|
|
83
|
+
return listJobs(`/v1/organisations/${organisationId}/jobs`, title, page, search);
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
export async function listOrganisationShares(jobId: number): Promise<JobShare[]> {
|
package/src/api/resources.ts
CHANGED
|
@@ -48,32 +48,7 @@ export type CustomFeature =
|
|
|
48
48
|
| 'hosted_svg_output'
|
|
49
49
|
| 'hosted_png_output'
|
|
50
50
|
| 'hosted_jpg_output'
|
|
51
|
-
| 'developer_menu'
|
|
52
|
-
| 'allow_editing_other_users_jobs';
|
|
53
|
-
|
|
54
|
-
export type ApiJobFolder = {
|
|
55
|
-
id: number;
|
|
56
|
-
organisation_id: number;
|
|
57
|
-
name: string;
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
export type JobFolder = {
|
|
61
|
-
id: number;
|
|
62
|
-
organisationId: number;
|
|
63
|
-
name: string;
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
export type ApiAccessibleOrganisation = {
|
|
67
|
-
id: number;
|
|
68
|
-
name: string;
|
|
69
|
-
job_folders: ApiJobFolder[];
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
export type AccessibleOrganisation = {
|
|
73
|
-
id: number;
|
|
74
|
-
name: string;
|
|
75
|
-
jobFolders: JobFolder[];
|
|
76
|
-
};
|
|
51
|
+
| 'developer_menu';
|
|
77
52
|
|
|
78
53
|
export interface Resources {
|
|
79
54
|
organisation: Organisation;
|
|
@@ -90,7 +65,6 @@ export interface Resources {
|
|
|
90
65
|
layers: Layer[];
|
|
91
66
|
fonts: Font[];
|
|
92
67
|
fontFamilies: FontFamily[];
|
|
93
|
-
accessibleOrganisations: AccessibleOrganisation[];
|
|
94
68
|
}
|
|
95
69
|
|
|
96
70
|
type ApiResources = {
|
|
@@ -113,7 +87,6 @@ type ApiResources = {
|
|
|
113
87
|
layers: ApiLayerData[];
|
|
114
88
|
fonts: ApiFontData[];
|
|
115
89
|
font_families: ApiFontFamilyData[];
|
|
116
|
-
accessible_organisations: ApiAccessibleOrganisation[];
|
|
117
90
|
} & ApiCommonData;
|
|
118
91
|
} & Omit<ApiSuccess, 'data'> | ApiError;
|
|
119
92
|
|
|
@@ -158,10 +131,6 @@ export async function loadResources(): Promise<Resources> {
|
|
|
158
131
|
svgSets: (raw.svgSets?.map(processData, getContext(svgSetRevivers)) ?? []) as SvgSet[],
|
|
159
132
|
fonts: (raw.fonts?.map(processData, getContext(fontRevivers)) ?? []) as Font[],
|
|
160
133
|
fontFamilies: (raw.fontFamilies?.map(processData, getContext(fontFamilyRevivers)) ?? []) as FontFamily[],
|
|
161
|
-
// TODO revivers and such
|
|
162
|
-
accessibleOrganisations: (raw.accessibleOrganisations?.map(
|
|
163
|
-
processData, getContext({})
|
|
164
|
-
) ?? []) as AccessibleOrganisation[],
|
|
165
134
|
};
|
|
166
135
|
}
|
|
167
136
|
|