@things-factory/scheduler 8.0.0-beta.9 → 8.0.2
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/client/bootstrap.ts +1 -0
- package/client/index.ts +0 -0
- package/client/pages/scheduler/popup-crontab-input.ts +75 -0
- package/client/pages/scheduler/schedule-list-page.ts +326 -0
- package/client/pages/scheduler/schedule-popup.ts +484 -0
- package/client/route.ts +7 -0
- package/client/tsconfig.json +11 -0
- package/client/types.ts +34 -0
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -7
- package/server/controllers/index.ts +0 -0
- package/server/index.ts +3 -0
- package/server/routes.ts +28 -0
- package/server/service/index.ts +25 -0
- package/server/service/schedule/index.ts +7 -0
- package/server/service/schedule/schedule-mutation.ts +34 -0
- package/server/service/schedule/schedule-query.ts +64 -0
- package/server/service/schedule/schedule-type.ts +194 -0
- package/server/tsconfig.json +10 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@things-factory/scheduler",
|
|
3
|
-
"version": "8.0.
|
|
3
|
+
"version": "8.0.2",
|
|
4
4
|
"main": "dist-server/index.js",
|
|
5
5
|
"browser": "dist-client/index.js",
|
|
6
6
|
"things-factory": true,
|
|
@@ -27,11 +27,12 @@
|
|
|
27
27
|
"migration:create": "node ../../node_modules/typeorm/cli.js migration:create ./server/migrations/migration"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@operato/graphql": "^8.0.0
|
|
31
|
-
"@operato/
|
|
32
|
-
"@
|
|
33
|
-
"@things-factory/
|
|
34
|
-
"@things-factory/
|
|
30
|
+
"@operato/graphql": "^8.0.0",
|
|
31
|
+
"@operato/input": "^8.0.0",
|
|
32
|
+
"@operato/shell": "^8.0.0",
|
|
33
|
+
"@things-factory/auth-base": "^8.0.2",
|
|
34
|
+
"@things-factory/scheduler-client": "^8.0.2",
|
|
35
|
+
"@things-factory/shell": "^8.0.2"
|
|
35
36
|
},
|
|
36
|
-
"gitHead": "
|
|
37
|
+
"gitHead": "39d60f56e142561233ddf6d47b539c637971357c"
|
|
37
38
|
}
|
|
File without changes
|
package/server/index.ts
ADDED
package/server/routes.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const debug = require('debug')('things-factory:scheduler:routes')
|
|
2
|
+
|
|
3
|
+
process.on('bootstrap-module-global-public-route' as any, (app, globalPublicRouter) => {
|
|
4
|
+
/*
|
|
5
|
+
* can add global public routes to application (auth not required, tenancy not required)
|
|
6
|
+
*
|
|
7
|
+
* ex) routes.get('/path', async(context, next) => {})
|
|
8
|
+
* ex) routes.post('/path', async(context, next) => {})
|
|
9
|
+
*/
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
process.on('bootstrap-module-global-private-route' as any, (app, globalPrivateRouter) => {
|
|
13
|
+
/*
|
|
14
|
+
* can add global private routes to application (auth required, tenancy not required)
|
|
15
|
+
*/
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
process.on('bootstrap-module-domain-public-route' as any, (app, domainPublicRouter) => {
|
|
19
|
+
/*
|
|
20
|
+
* can add domain public routes to application (auth not required, tenancy required)
|
|
21
|
+
*/
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
process.on('bootstrap-module-domain-private-route' as any, (app, domainPrivateRouter) => {
|
|
25
|
+
/*
|
|
26
|
+
* can add domain private routes to application (auth required, tenancy required)
|
|
27
|
+
*/
|
|
28
|
+
})
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/* EXPORT ENTITY TYPES */
|
|
2
|
+
|
|
3
|
+
/* IMPORT ENTITIES AND RESOLVERS */
|
|
4
|
+
import {
|
|
5
|
+
entities as SchedulerEntities,
|
|
6
|
+
resolvers as SchedulerResolvers,
|
|
7
|
+
subscribers as SchedulerSubscribers
|
|
8
|
+
} from './schedule'
|
|
9
|
+
|
|
10
|
+
export const entities = [
|
|
11
|
+
/* ENTITIES */
|
|
12
|
+
...SchedulerEntities
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
export const subscribers = [
|
|
16
|
+
/* SUBSCRIBERS */
|
|
17
|
+
...SchedulerSubscribers
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
export const schema = {
|
|
21
|
+
resolverClasses: [
|
|
22
|
+
/* RESOLVER CLASSES */
|
|
23
|
+
...SchedulerResolvers
|
|
24
|
+
]
|
|
25
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Schedule } from './schedule-type'
|
|
2
|
+
import { ScheduleQuery } from './schedule-query'
|
|
3
|
+
import { ScheduleMutation } from './schedule-mutation'
|
|
4
|
+
|
|
5
|
+
export const entities = [Schedule]
|
|
6
|
+
export const resolvers = [ScheduleQuery, ScheduleMutation]
|
|
7
|
+
export const subscribers = []
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Resolver, Directive, Mutation, Arg, ID } from 'type-graphql'
|
|
2
|
+
|
|
3
|
+
import { registerSchedule, updateSchedule, unregisterSchedule } from '@things-factory/scheduler-client'
|
|
4
|
+
import { Schedule, NewSchedule, SchedulePatch } from './schedule-type'
|
|
5
|
+
|
|
6
|
+
@Resolver(Schedule)
|
|
7
|
+
export class ScheduleMutation {
|
|
8
|
+
@Directive('@privilege(superUserGranted: true)')
|
|
9
|
+
@Mutation(() => ID)
|
|
10
|
+
async registerSchedule(@Arg('schedule') schedule: NewSchedule): Promise<string> {
|
|
11
|
+
var handle = await registerSchedule(schedule)
|
|
12
|
+
|
|
13
|
+
return handle
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@Directive('@privilege(superUserGranted: true)')
|
|
17
|
+
@Mutation(() => ID)
|
|
18
|
+
async updateSchedule(@Arg('schedule') schedule: SchedulePatch): Promise<string> {
|
|
19
|
+
return await updateSchedule(schedule)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@Directive('@privilege(superUserGranted: true)')
|
|
23
|
+
@Mutation(() => Boolean)
|
|
24
|
+
async unregisterSchedule(@Arg('handle', () => ID) handle: string): Promise<boolean> {
|
|
25
|
+
try {
|
|
26
|
+
await unregisterSchedule(handle)
|
|
27
|
+
} catch (error) {
|
|
28
|
+
console.error(error)
|
|
29
|
+
return false
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return true
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Resolver, Query, Args, Arg, Ctx, Directive, ID } from 'type-graphql'
|
|
2
|
+
import { ListParam } from '@things-factory/shell'
|
|
3
|
+
import { User } from '@things-factory/auth-base'
|
|
4
|
+
import { getSchedules, getSchedule } from '@things-factory/scheduler-client'
|
|
5
|
+
import { Schedule, ScheduleList } from './schedule-type'
|
|
6
|
+
|
|
7
|
+
@Resolver(Schedule)
|
|
8
|
+
export class ScheduleQuery {
|
|
9
|
+
@Directive('@privilege(superUserGranted: true)')
|
|
10
|
+
@Query(() => Schedule, { nullable: true })
|
|
11
|
+
async schedule(@Arg('id', () => ID) id: string): Promise<Schedule | null> {
|
|
12
|
+
return await getSchedule(id)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@Directive('@privilege(superUserGranted: true)')
|
|
16
|
+
@Query(returns => ScheduleList, { description: 'To fetch multiple Schedules' })
|
|
17
|
+
async schedules(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<ScheduleList> {
|
|
18
|
+
const filters = params.filters || []
|
|
19
|
+
|
|
20
|
+
const name = filters.find(filter => filter.name == 'name')?.value
|
|
21
|
+
|
|
22
|
+
const application = filters.find(filter => filter.name == 'application')?.value
|
|
23
|
+
const group = filters.find(filter => filter.name == 'group')?.value
|
|
24
|
+
const type = filters.find(filter => filter.name == 'type')?.value
|
|
25
|
+
const key = filters.find(filter => filter.name == 'key')?.value
|
|
26
|
+
const operation = filters.find(filter => filter.name == 'operation')?.value
|
|
27
|
+
|
|
28
|
+
var schedules = await getSchedules({})
|
|
29
|
+
|
|
30
|
+
if (name) {
|
|
31
|
+
schedules = schedules.filter(schedule => (schedule.name || '').toLowerCase().includes(name.toLowerCase()))
|
|
32
|
+
}
|
|
33
|
+
if (application) {
|
|
34
|
+
schedules = schedules.filter(schedule =>
|
|
35
|
+
(schedule.client?.application || '').toLowerCase().includes(application.toLowerCase())
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
if (group) {
|
|
39
|
+
schedules = schedules.filter(schedule =>
|
|
40
|
+
(schedule.client?.group || '').toLowerCase().includes(group.toLowerCase())
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
if (type) {
|
|
44
|
+
schedules = schedules.filter(schedule => (schedule.client?.type || '').toLowerCase().includes(type.toLowerCase()))
|
|
45
|
+
}
|
|
46
|
+
if (key) {
|
|
47
|
+
schedules = schedules.filter(schedule => (schedule.client?.key || '').toLowerCase().includes(key.toLowerCase()))
|
|
48
|
+
}
|
|
49
|
+
if (operation) {
|
|
50
|
+
schedules = schedules.filter(schedule =>
|
|
51
|
+
(schedule.client?.operation || '').toLowerCase().includes(operation.toLowerCase())
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const { page = 1, limit = 20 } = params.pagination || {}
|
|
56
|
+
|
|
57
|
+
const start = (page - 1) * limit
|
|
58
|
+
const end = start + limit
|
|
59
|
+
const items = schedules.slice(start, end)
|
|
60
|
+
const total = schedules.length
|
|
61
|
+
|
|
62
|
+
return { items, total }
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { ObjectType, Field, InputType, Int, ID } from 'type-graphql'
|
|
2
|
+
import { ScalarObject } from '@things-factory/shell'
|
|
3
|
+
|
|
4
|
+
@ObjectType()
|
|
5
|
+
export class ScheduleClient {
|
|
6
|
+
@Field()
|
|
7
|
+
application: string
|
|
8
|
+
|
|
9
|
+
@Field()
|
|
10
|
+
group: string
|
|
11
|
+
|
|
12
|
+
@Field()
|
|
13
|
+
type: string
|
|
14
|
+
|
|
15
|
+
@Field()
|
|
16
|
+
key: string
|
|
17
|
+
|
|
18
|
+
@Field()
|
|
19
|
+
operation: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@ObjectType()
|
|
23
|
+
export class ScheduleTaskConnection {
|
|
24
|
+
@Field({ nullable: true })
|
|
25
|
+
host?: string
|
|
26
|
+
|
|
27
|
+
@Field(type => ScalarObject, { nullable: true })
|
|
28
|
+
headers?: Record<string, string>
|
|
29
|
+
|
|
30
|
+
@Field({ nullable: true })
|
|
31
|
+
topic?: string
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@ObjectType()
|
|
35
|
+
export class ScheduleTask {
|
|
36
|
+
@Field()
|
|
37
|
+
type: string
|
|
38
|
+
|
|
39
|
+
@Field(type => ScheduleTaskConnection)
|
|
40
|
+
connection: ScheduleTaskConnection
|
|
41
|
+
|
|
42
|
+
@Field(type => ScalarObject)
|
|
43
|
+
data: Record<string, any>
|
|
44
|
+
|
|
45
|
+
@Field()
|
|
46
|
+
history_check: boolean
|
|
47
|
+
|
|
48
|
+
@Field()
|
|
49
|
+
failed_policy: 'ignore' | 'retry' | 'retry_dlq'
|
|
50
|
+
|
|
51
|
+
@Field(type => Int)
|
|
52
|
+
retry_wait: number
|
|
53
|
+
|
|
54
|
+
@Field(type => Int)
|
|
55
|
+
retry_count: number
|
|
56
|
+
|
|
57
|
+
@Field(type => Int)
|
|
58
|
+
max_retry_count: number
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@ObjectType()
|
|
62
|
+
export class Schedule {
|
|
63
|
+
@Field(type => ID)
|
|
64
|
+
id: string
|
|
65
|
+
|
|
66
|
+
@Field({ nullable: true })
|
|
67
|
+
name?: string
|
|
68
|
+
|
|
69
|
+
@Field(type => ScheduleClient)
|
|
70
|
+
client: ScheduleClient
|
|
71
|
+
|
|
72
|
+
@Field()
|
|
73
|
+
type: 'now' | 'delay' | 'date' | 'cron' | 'delay-recur'
|
|
74
|
+
|
|
75
|
+
@Field({ nullable: true })
|
|
76
|
+
schedule?: string
|
|
77
|
+
|
|
78
|
+
@Field({ nullable: true })
|
|
79
|
+
timezone?: string
|
|
80
|
+
|
|
81
|
+
@Field(type => ScheduleTask)
|
|
82
|
+
task: ScheduleTask
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@InputType()
|
|
86
|
+
class ScheduleClientInput {
|
|
87
|
+
@Field()
|
|
88
|
+
application: string
|
|
89
|
+
|
|
90
|
+
@Field()
|
|
91
|
+
group: string
|
|
92
|
+
|
|
93
|
+
@Field()
|
|
94
|
+
type: string
|
|
95
|
+
|
|
96
|
+
@Field()
|
|
97
|
+
key: string
|
|
98
|
+
|
|
99
|
+
@Field()
|
|
100
|
+
operation: string
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
@InputType()
|
|
104
|
+
export class ScheduleTaskConnectionInput {
|
|
105
|
+
@Field({ nullable: true })
|
|
106
|
+
host?: string
|
|
107
|
+
|
|
108
|
+
@Field(type => ScalarObject, { nullable: true })
|
|
109
|
+
headers?: Record<string, string>
|
|
110
|
+
|
|
111
|
+
@Field({ nullable: true })
|
|
112
|
+
topic?: string
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
@InputType()
|
|
116
|
+
class ScheduleTaskInput {
|
|
117
|
+
@Field()
|
|
118
|
+
type: 'rest' | 'kafka' | 'redis'
|
|
119
|
+
|
|
120
|
+
@Field(type => ScheduleTaskConnectionInput)
|
|
121
|
+
connection: ScheduleTaskConnectionInput
|
|
122
|
+
|
|
123
|
+
@Field(type => ScalarObject)
|
|
124
|
+
data: Record<string, any>
|
|
125
|
+
|
|
126
|
+
@Field()
|
|
127
|
+
history_check: boolean
|
|
128
|
+
|
|
129
|
+
@Field()
|
|
130
|
+
failed_policy: 'ignore' | 'retry' | 'retry_dlq'
|
|
131
|
+
|
|
132
|
+
@Field(type => Int)
|
|
133
|
+
retry_wait: number
|
|
134
|
+
|
|
135
|
+
@Field(type => Int)
|
|
136
|
+
retry_count: number
|
|
137
|
+
|
|
138
|
+
@Field(type => Int)
|
|
139
|
+
max_retry_count: number
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
@InputType()
|
|
143
|
+
export class NewSchedule {
|
|
144
|
+
@Field()
|
|
145
|
+
name: string
|
|
146
|
+
|
|
147
|
+
@Field(type => ScheduleClientInput)
|
|
148
|
+
client: ScheduleClientInput
|
|
149
|
+
|
|
150
|
+
@Field()
|
|
151
|
+
type: 'now' | 'delay' | 'date' | 'cron' | 'delay-recur'
|
|
152
|
+
|
|
153
|
+
@Field({ nullable: true })
|
|
154
|
+
schedule: string
|
|
155
|
+
|
|
156
|
+
@Field({ nullable: true })
|
|
157
|
+
timezone: string
|
|
158
|
+
|
|
159
|
+
@Field(type => ScheduleTaskInput)
|
|
160
|
+
task: ScheduleTaskInput
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
@InputType()
|
|
164
|
+
export class SchedulePatch {
|
|
165
|
+
@Field({ nullable: true })
|
|
166
|
+
id: string
|
|
167
|
+
|
|
168
|
+
@Field({ nullable: true })
|
|
169
|
+
name?: string
|
|
170
|
+
|
|
171
|
+
@Field(type => ScheduleClientInput)
|
|
172
|
+
client: ScheduleClientInput
|
|
173
|
+
|
|
174
|
+
@Field()
|
|
175
|
+
type: 'now' | 'delay' | 'date' | 'cron' | 'delay-recur'
|
|
176
|
+
|
|
177
|
+
@Field({ nullable: true })
|
|
178
|
+
schedule: string
|
|
179
|
+
|
|
180
|
+
@Field({ nullable: true })
|
|
181
|
+
timezone: string
|
|
182
|
+
|
|
183
|
+
@Field(type => ScheduleTaskInput)
|
|
184
|
+
task: ScheduleTaskInput
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
@ObjectType()
|
|
188
|
+
export class ScheduleList {
|
|
189
|
+
@Field(type => [Schedule])
|
|
190
|
+
items: Schedule[]
|
|
191
|
+
|
|
192
|
+
@Field(type => Int)
|
|
193
|
+
total: number
|
|
194
|
+
}
|