@things-factory/calendar 8.0.0 → 9.0.0-beta.3

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.
Files changed (36) hide show
  1. package/dist-client/tsconfig.tsbuildinfo +1 -1
  2. package/dist-server/tsconfig.tsbuildinfo +1 -1
  3. package/package.json +7 -7
  4. package/client/bootstrap.ts +0 -1
  5. package/client/index.ts +0 -0
  6. package/client/pages/attendee/attendee-importer.ts +0 -87
  7. package/client/pages/attendee/attendee-list-page.ts +0 -324
  8. package/client/pages/calendar/calendar-importer.ts +0 -87
  9. package/client/pages/calendar/calendar-list-page.ts +0 -325
  10. package/client/pages/calendar/calendar-page.ts +0 -128
  11. package/client/pages/event/event-importer.ts +0 -87
  12. package/client/pages/event/event-list-page.ts +0 -324
  13. package/client/route.ts +0 -19
  14. package/client/tsconfig.json +0 -13
  15. package/server/controllers/index.ts +0 -0
  16. package/server/index.ts +0 -4
  17. package/server/middlewares/index.ts +0 -3
  18. package/server/migrations/index.ts +0 -9
  19. package/server/routes.ts +0 -28
  20. package/server/service/attendee/attendee-mutation.ts +0 -122
  21. package/server/service/attendee/attendee-query.ts +0 -31
  22. package/server/service/attendee/attendee-type.ts +0 -44
  23. package/server/service/attendee/attendee.ts +0 -37
  24. package/server/service/attendee/index.ts +0 -7
  25. package/server/service/calendar/calendar-mutation.ts +0 -133
  26. package/server/service/calendar/calendar-query.ts +0 -48
  27. package/server/service/calendar/calendar-type.ts +0 -55
  28. package/server/service/calendar/calendar.ts +0 -82
  29. package/server/service/calendar/index.ts +0 -7
  30. package/server/service/event/event-mutation.ts +0 -125
  31. package/server/service/event/event-query.ts +0 -38
  32. package/server/service/event/event-type.ts +0 -61
  33. package/server/service/event/event.ts +0 -85
  34. package/server/service/event/index.ts +0 -7
  35. package/server/service/index.ts +0 -32
  36. package/server/tsconfig.json +0 -10
@@ -1,324 +0,0 @@
1
- import '@operato/data-grist'
2
-
3
- import { CommonButtonStyles, CommonHeaderStyles, CommonGristStyles, ScrollbarStyles } from '@operato/styles'
4
- import { PageView, store } from '@operato/shell'
5
- import { css, html } from 'lit'
6
- import { customElement, property, query } from 'lit/decorators.js'
7
- import { ScopedElementsMixin } from '@open-wc/scoped-elements'
8
- import { ColumnConfig, DataGrist, FetchOption } from '@operato/data-grist'
9
- import { client } from '@operato/graphql'
10
- import { i18next, localize } from '@operato/i18n'
11
- import { notify, openPopup } from '@operato/layout'
12
- import { isMobileDevice } from '@operato/utils'
13
-
14
- import { connect } from 'pwa-helpers/connect-mixin'
15
- import gql from 'graphql-tag'
16
-
17
- import { EventImporter } from './event-importer'
18
-
19
- @customElement('event-list-page')
20
- export class EventListPage extends connect(store)(localize(i18next)(ScopedElementsMixin(PageView))) {
21
- static styles = [
22
- ScrollbarStyles,
23
- CommonGristStyles,
24
- CommonHeaderStyles,
25
- css`
26
- :host {
27
- display: flex;
28
-
29
- width: 100%;
30
-
31
- --grid-record-emphasized-background-color: #8b0000;
32
- --grid-record-emphasized-color: #ff6b6b;
33
- }
34
-
35
- ox-grist {
36
- overflow-y: auto;
37
- flex: 1;
38
- }
39
-
40
- ox-filters-form {
41
- flex: 1;
42
- }
43
- `
44
- ]
45
-
46
- static get scopedElements() {
47
- return {
48
- 'event-importer': EventImporter
49
- }
50
- }
51
-
52
- @property({ type: Object }) gristConfig: any
53
- @property({ type: String }) mode: 'CARD' | 'GRID' | 'LIST' = isMobileDevice() ? 'CARD' : 'GRID'
54
-
55
- @query('ox-grist') private grist!: DataGrist
56
-
57
- get context() {
58
- return {
59
- title: i18next.t('title.event list'),
60
- search: {
61
- handler: (search: string) => {
62
- this.grist.searchText = search
63
- },
64
- value: this.grist?.searchText || '',
65
- autofocus: true
66
- },
67
- filter: {
68
- handler: () => {
69
- this.grist.toggleHeadroom()
70
- }
71
- },
72
- help: 'calendar/event',
73
- actions: [
74
- {
75
- title: i18next.t('button.save'),
76
- action: this._updateEvent.bind(this),
77
- ...CommonButtonStyles.save
78
- },
79
- {
80
- title: i18next.t('button.delete'),
81
- action: this._deleteEvent.bind(this),
82
- ...CommonButtonStyles.delete
83
- }
84
- ],
85
- exportable: {
86
- name: i18next.t('title.event list'),
87
- data: this.exportHandler.bind(this)
88
- },
89
- importable: {
90
- handler: this.importHandler.bind(this)
91
- }
92
- }
93
- }
94
-
95
- render() {
96
- const mode = this.mode || (isMobileDevice() ? 'CARD' : 'GRID')
97
-
98
- return html`
99
- <ox-grist .mode=${mode} .config=${this.gristConfig} .fetchHandler=${this.fetchHandler.bind(this)}>
100
- <div slot="headroom" class="header">
101
- <div class="filters">
102
- <ox-filters-form autofocus></ox-filters-form>
103
-
104
- <div id="modes">
105
- <md-icon @click=${() => (this.mode = 'GRID')} ?active=${mode == 'GRID'}>grid_on</md-icon>
106
- <md-icon @click=${() => (this.mode = 'LIST')} ?active=${mode == 'LIST'}>format_list_bulleted</md-icon>
107
- <md-icon @click=${() => (this.mode = 'CARD')} ?active=${mode == 'CARD'}>apps</md-icon>
108
- </div>
109
- </div>
110
- </div>
111
- </ox-grist>
112
- `
113
- }
114
-
115
- async pageInitialized(lifecycle: any) {
116
- this.gristConfig = {
117
- list: {
118
- fields: ['name', 'description'],
119
- details: ['active', 'updatedAt']
120
- },
121
- columns: [
122
- { type: 'gutter', gutterName: 'sequence' },
123
- { type: 'gutter', gutterName: 'row-selector', multiple: true },
124
- {
125
- type: 'string',
126
- name: 'name',
127
- header: i18next.t('field.name'),
128
- record: {
129
- editable: true
130
- },
131
- filter: 'search',
132
- sortable: true,
133
- width: 150
134
- },
135
- {
136
- type: 'string',
137
- name: 'description',
138
- header: i18next.t('field.description'),
139
- record: {
140
- editable: true
141
- },
142
- filter: 'search',
143
- width: 200
144
- },
145
- {
146
- type: 'checkbox',
147
- name: 'active',
148
- label: true,
149
- header: i18next.t('field.active'),
150
- record: {
151
- editable: true
152
- },
153
- filter: true,
154
- sortable: true,
155
- width: 60
156
- },
157
- {
158
- type: 'resource-object',
159
- name: 'updater',
160
- header: i18next.t('field.updater'),
161
- record: {
162
- editable: false
163
- },
164
- sortable: true,
165
- width: 120
166
- },
167
- {
168
- type: 'datetime',
169
- name: 'updatedAt',
170
- header: i18next.t('field.updated_at'),
171
- record: {
172
- editable: false
173
- },
174
- sortable: true,
175
- width: 180
176
- }
177
- ],
178
- rows: {
179
- selectable: {
180
- multiple: true
181
- }
182
- },
183
- sorters: [
184
- {
185
- name: 'name'
186
- }
187
- ]
188
- }
189
- }
190
-
191
- async pageUpdated(changes: any, lifecycle: any) {
192
- if (this.active) {
193
- // do something here when this page just became as active
194
- }
195
- }
196
-
197
- async fetchHandler({ page = 1, limit = 100, sortings = [], filters = [] }: FetchOption) {
198
- const response = await client.query({
199
- query: gql`
200
- query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
201
- responses: events(filters: $filters, pagination: $pagination, sortings: $sortings) {
202
- items {
203
- id
204
- name
205
- description
206
- active
207
- updater {
208
- id
209
- name
210
- }
211
- updatedAt
212
- }
213
- total
214
- }
215
- }
216
- `,
217
- variables: {
218
- filters,
219
- pagination: { page, limit },
220
- sortings
221
- }
222
- })
223
-
224
- return {
225
- total: response.data.responses.total || 0,
226
- records: response.data.responses.items || []
227
- }
228
- }
229
-
230
- async _deleteEvent() {
231
- if (confirm(i18next.t('text.sure_to_x', { x: i18next.t('text.delete') }))) {
232
- const ids = this.grist.selected.map(record => record.id)
233
- if (ids && ids.length > 0) {
234
- const response = await client.mutate({
235
- mutation: gql`
236
- mutation ($ids: [String!]!) {
237
- deleteEvents(ids: $ids)
238
- }
239
- `,
240
- variables: {
241
- ids
242
- }
243
- })
244
-
245
- if (!response.errors) {
246
- this.grist.fetch()
247
- notify({
248
- message: i18next.t('text.info_x_successfully', { x: i18next.t('text.delete') })
249
- })
250
- }
251
- }
252
- }
253
- }
254
-
255
- async _updateEvent() {
256
- let patches = this.grist.dirtyRecords
257
- if (patches && patches.length) {
258
- patches = patches.map(patch => {
259
- let patchField: any = patch.id ? { id: patch.id } : {}
260
- const dirtyFields = patch.__dirtyfields__
261
- for (let key in dirtyFields) {
262
- patchField[key] = dirtyFields[key].after
263
- }
264
- patchField.cuFlag = patch.__dirty__
265
-
266
- return patchField
267
- })
268
-
269
- const response = await client.mutate({
270
- mutation: gql`
271
- mutation ($patches: [EventPatch!]!) {
272
- updateMultipleEvent(patches: $patches) {
273
- name
274
- }
275
- }
276
- `,
277
- variables: {
278
- patches
279
- }
280
- })
281
-
282
- if (!response.errors) {
283
- this.grist.fetch()
284
- }
285
- }
286
- }
287
-
288
- async exportHandler() {
289
- const exportTargets = this.grist.selected.length ? this.grist.selected : this.grist.dirtyData.records
290
- const targetFieldSet = new Set(['id', 'name', 'description', 'active'])
291
-
292
- return exportTargets.map(event => {
293
- let tempObj = {}
294
- for (const field of targetFieldSet) {
295
- tempObj[field] = event[field]
296
- }
297
-
298
- return tempObj
299
- })
300
- }
301
-
302
- async importHandler(records) {
303
- const popup = openPopup(
304
- html`
305
- <event-importer
306
- .events=${records}
307
- @imported=${() => {
308
- history.back()
309
- this.grist.fetch()
310
- }}
311
- ></event-importer>
312
- `,
313
- {
314
- backdrop: true,
315
- size: 'large',
316
- title: i18next.t('title.import event')
317
- }
318
- )
319
-
320
- popup.onclosed = () => {
321
- this.grist.fetch()
322
- }
323
- }
324
- }
package/client/route.ts DELETED
@@ -1,19 +0,0 @@
1
- export default function route(page: string) {
2
- switch (page) {
3
- case 'calendar':
4
- import('./pages/calendar/calendar-page')
5
- return page
6
-
7
- case 'calendar-list':
8
- import('./pages/calendar/calendar-list-page')
9
- return page
10
-
11
- case 'event-list':
12
- import('./pages/event/event-list-page')
13
- return page
14
-
15
- case 'attendee-list':
16
- import('./pages/attendee/attendee-list-page')
17
- return page
18
- }
19
- }
@@ -1,13 +0,0 @@
1
- {
2
- "extends": "../../tsconfig-base.json",
3
- "compilerOptions": {
4
- "experimentalDecorators": true,
5
- "skipLibCheck": true,
6
- "strict": true,
7
- "declaration": true,
8
- "module": "esnext",
9
- "outDir": "../dist-client",
10
- "baseUrl": "./"
11
- },
12
- "include": ["./**/*"]
13
- }
File without changes
package/server/index.ts DELETED
@@ -1,4 +0,0 @@
1
- export * from './migrations'
2
- export * from './middlewares'
3
-
4
- import './routes'
@@ -1,3 +0,0 @@
1
- export function initMiddlewares(app) {
2
- /* can add middlewares into app */
3
- }
@@ -1,9 +0,0 @@
1
- const glob = require('glob')
2
- const path = require('path')
3
-
4
- export var migrations = []
5
-
6
- glob.sync(path.resolve(__dirname, '.', '**', '*.js')).forEach(function(file) {
7
- if (file.indexOf('index.js') !== -1) return
8
- migrations = migrations.concat(Object.values(require(path.resolve(file))) || [])
9
- })
package/server/routes.ts DELETED
@@ -1,28 +0,0 @@
1
- const debug = require('debug')('things-factory:calendar: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
- })
@@ -1,122 +0,0 @@
1
- import { Resolver, Mutation, Arg, Ctx, Directive } from 'type-graphql'
2
- import { In } from 'typeorm'
3
-
4
- import { Attendee } from './attendee'
5
- import { NewAttendee, AttendeePatch } from './attendee-type'
6
-
7
- @Resolver(Attendee)
8
- export class AttendeeMutation {
9
- @Directive('@transaction')
10
- @Mutation(returns => Attendee, { description: 'To create new Attendee' })
11
- async createAttendee(@Arg('attendee') attendee: NewAttendee, @Ctx() context: ResolverContext): Promise<Attendee> {
12
- const { tx } = context.state
13
-
14
- return await tx.getRepository(Attendee).save({
15
- ...attendee
16
- })
17
- }
18
-
19
- @Directive('@transaction')
20
- @Mutation(returns => Attendee, { description: 'To modify Attendee information' })
21
- async updateAttendee(
22
- @Arg('id') id: string,
23
- @Arg('patch') patch: AttendeePatch,
24
- @Ctx() context: ResolverContext
25
- ): Promise<Attendee> {
26
- const { tx } = context.state
27
-
28
- const repository = tx.getRepository(Attendee)
29
- const attendee = await repository.findOne({
30
- where: { id }
31
- })
32
-
33
- return await repository.save({
34
- ...attendee,
35
- ...patch
36
- })
37
- }
38
-
39
- @Directive('@transaction')
40
- @Mutation(returns => [Attendee], { description: "To modify multiple Attendees' information" })
41
- async updateMultipleAttendee(
42
- @Arg('patches', type => [AttendeePatch]) patches: AttendeePatch[],
43
- @Ctx() context: ResolverContext
44
- ): Promise<Attendee[]> {
45
- const { user, tx } = context.state
46
-
47
- let results = []
48
- const _createRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === '+')
49
- const _updateRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === 'M')
50
- const attendeeRepo = tx.getRepository(Attendee)
51
-
52
- if (_createRecords.length > 0) {
53
- for (let i = 0; i < _createRecords.length; i++) {
54
- const newRecord = _createRecords[i]
55
-
56
- const result = await attendeeRepo.save({
57
- ...newRecord
58
- })
59
-
60
- results.push({ ...result, cuFlag: '+' })
61
- }
62
- }
63
-
64
- if (_updateRecords.length > 0) {
65
- for (let i = 0; i < _updateRecords.length; i++) {
66
- const updateRecord = _updateRecords[i]
67
- const attendee = await attendeeRepo.findOneBy({ id: updateRecord.id })
68
-
69
- const result = await attendeeRepo.save({
70
- ...attendee,
71
- ...updateRecord
72
- })
73
-
74
- results.push({ ...result, cuFlag: 'M' })
75
- }
76
- }
77
-
78
- return results
79
- }
80
-
81
- @Directive('@transaction')
82
- @Mutation(returns => Boolean, { description: 'To delete Attendee' })
83
- async deleteAttendee(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<boolean> {
84
- const { tx } = context.state
85
-
86
- await tx.getRepository(Attendee).delete({ id })
87
-
88
- return true
89
- }
90
-
91
- @Directive('@transaction')
92
- @Mutation(returns => Boolean, { description: 'To delete multiple Attendees' })
93
- async deleteAttendees(
94
- @Arg('ids', type => [String]) ids: string[],
95
- @Ctx() context: ResolverContext
96
- ): Promise<boolean> {
97
- const { tx } = context.state
98
-
99
- await tx.getRepository(Attendee).delete({
100
- id: In(ids)
101
- })
102
-
103
- return true
104
- }
105
-
106
- @Directive('@transaction')
107
- @Mutation(returns => Boolean, { description: 'To import multiple Attendees' })
108
- async importAttendees(
109
- @Arg('attendees', type => [AttendeePatch]) attendees: AttendeePatch[],
110
- @Ctx() context: ResolverContext
111
- ): Promise<boolean> {
112
- const { tx } = context.state
113
-
114
- await Promise.all(
115
- attendees.map(async (attendee: AttendeePatch) => {
116
- const createdAttendee: Attendee = await tx.getRepository(Attendee).save({ ...attendee })
117
- })
118
- )
119
-
120
- return true
121
- }
122
- }
@@ -1,31 +0,0 @@
1
- import { Resolver, Query, FieldResolver, Root, Args, Arg, Ctx, Directive } from 'type-graphql'
2
- import { getQueryBuilderFromListParams, getRepository, ListParam } from '@things-factory/shell'
3
- import { User } from '@things-factory/auth-base'
4
- import { Attendee } from './attendee'
5
- import { AttendeeList } from './attendee-type'
6
-
7
- @Resolver(Attendee)
8
- export class AttendeeQuery {
9
- @Query(returns => Attendee!, { nullable: true, description: 'To fetch a Attendee' })
10
- async attendee(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Attendee> {
11
- return await getRepository(Attendee).findOne({
12
- where: { id }
13
- })
14
- }
15
-
16
- @Query(returns => AttendeeList, { description: 'To fetch multiple Attendees' })
17
- async attendees(@Args(type => ListParam) params: ListParam, @Ctx() context: ResolverContext): Promise<AttendeeList> {
18
- const { domain } = context.state
19
-
20
- const queryBuilder = getQueryBuilderFromListParams({
21
- domain,
22
- params,
23
- repository: await getRepository(Attendee),
24
- searchables: ['name', 'description']
25
- })
26
-
27
- const [items, total] = await queryBuilder.getManyAndCount()
28
-
29
- return { items, total }
30
- }
31
- }
@@ -1,44 +0,0 @@
1
- import { ObjectType, Field, InputType, Int, ID, registerEnumType } from 'type-graphql'
2
-
3
- import { ObjectRef, ScalarObject } from '@things-factory/shell'
4
-
5
- import { Attendee, AttendeeStatus } from './attendee'
6
-
7
- @InputType()
8
- export class NewAttendee {
9
- @Field()
10
- name: string
11
-
12
- @Field({ nullable: true })
13
- description?: string
14
-
15
- @Field(type => AttendeeStatus, { nullable: true })
16
- state?: AttendeeStatus
17
- }
18
-
19
- @InputType()
20
- export class AttendeePatch {
21
- @Field(type => ID, { nullable: true })
22
- id?: string
23
-
24
- @Field({ nullable: true })
25
- name?: string
26
-
27
- @Field({ nullable: true })
28
- description?: string
29
-
30
- @Field(type => AttendeeStatus, { nullable: true })
31
- state?: AttendeeStatus
32
-
33
- @Field({ nullable: true })
34
- cuFlag?: string
35
- }
36
-
37
- @ObjectType()
38
- export class AttendeeList {
39
- @Field(type => [Attendee])
40
- items: Attendee[]
41
-
42
- @Field(type => Int)
43
- total: number
44
- }
@@ -1,37 +0,0 @@
1
- import { Entity, Index, Column, ManyToMany, JoinTable, PrimaryGeneratedColumn } from 'typeorm'
2
- import { ObjectType, Field, Int, ID, registerEnumType } from 'type-graphql'
3
- import { GraphQLEmailAddress } from 'graphql-scalars'
4
-
5
- import { Event } from '../event/event'
6
-
7
- export enum AttendeeStatus {
8
- STATUS_A = 'STATUS_A',
9
- STATUS_B = 'STATUS_B'
10
- }
11
-
12
- registerEnumType(AttendeeStatus, {
13
- name: 'AttendeeStatus',
14
- description: 'state enumeration of a attendee'
15
- })
16
-
17
- @Entity()
18
- @Index('ix_attendee_0', (attendee: Attendee) => [attendee.email], { unique: false })
19
- @ObjectType({ description: 'Entity for Attendee' })
20
- export class Attendee {
21
- @PrimaryGeneratedColumn('uuid')
22
- @Field(type => ID)
23
- readonly id: string
24
-
25
- @Column()
26
- @Field({ nullable: true })
27
- name?: string
28
-
29
- @Column()
30
- @Field(type => GraphQLEmailAddress, { nullable: true })
31
- email: string
32
-
33
- @ManyToMany(() => Event)
34
- @JoinTable()
35
- @Field({ nullable: true })
36
- events: Event[]
37
- }
@@ -1,7 +0,0 @@
1
- import { Attendee } from './attendee'
2
- import { AttendeeQuery } from './attendee-query'
3
- import { AttendeeMutation } from './attendee-mutation'
4
-
5
- export const entities = [Attendee]
6
- export const resolvers = [AttendeeQuery, AttendeeMutation]
7
- export const subscribers = []