firstly 0.0.8 → 0.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.
Files changed (63) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/esm/BaseEnum.d.ts +3 -14
  3. package/esm/BaseEnum.js +0 -4
  4. package/esm/FF_Entity.d.ts +1 -1
  5. package/esm/FF_Entity.js +7 -3
  6. package/esm/ROUTES.d.ts +2 -2
  7. package/esm/api/index.d.ts +2 -3
  8. package/esm/api/index.js +4 -4
  9. package/esm/auth/RoleHelpers.d.ts +1 -1
  10. package/esm/auth/RoleHelpers.js +5 -3
  11. package/esm/auth/client/Auth.js +2 -2
  12. package/esm/auth/client/Entities.d.ts +2 -2
  13. package/esm/auth/client/Entities.js +5 -5
  14. package/esm/auth/client/index.d.ts +1 -1
  15. package/esm/auth/client/index.js +1 -1
  16. package/esm/auth/index.d.ts +2 -0
  17. package/esm/auth/index.js +23 -12
  18. package/esm/cellsBuildor.d.ts +4 -4
  19. package/esm/cellsBuildor.js +19 -6
  20. package/esm/feedback/FeedbackController.d.ts +1 -1
  21. package/esm/feedback/FeedbackController.js +0 -2
  22. package/esm/feedback/ui/DialogIssue.svelte +8 -8
  23. package/esm/handle/index.d.ts +0 -1
  24. package/esm/helper.d.ts +16 -14
  25. package/esm/helper.js +58 -2
  26. package/esm/index.d.ts +7 -3
  27. package/esm/index.js +1 -1
  28. package/esm/mail/index.js +15 -10
  29. package/esm/mail/templates/DefaultMail.svelte.d.ts +3 -3
  30. package/esm/storeItem.d.ts +1 -2
  31. package/esm/storeList.d.ts +4 -3
  32. package/esm/storeList.js +20 -10
  33. package/esm/ui/Clipboardable.svelte.d.ts +1 -1
  34. package/esm/ui/Field.svelte +9 -3
  35. package/esm/ui/Field.svelte.d.ts +3 -2
  36. package/esm/ui/FieldGroup.svelte +4 -2
  37. package/esm/ui/FieldGroup.svelte.d.ts +1 -1
  38. package/esm/ui/Grid.svelte +90 -20
  39. package/esm/ui/Grid.svelte.d.ts +6 -5
  40. package/esm/ui/GridLoading.svelte.d.ts +1 -1
  41. package/esm/ui/GridPaginate.svelte +6 -4
  42. package/esm/ui/GridPaginate.svelte.d.ts +2 -2
  43. package/esm/ui/Icon.svelte.d.ts +3 -3
  44. package/esm/ui/Loading.svelte.d.ts +1 -1
  45. package/esm/ui/Tooltip.svelte.d.ts +2 -2
  46. package/esm/ui/dialog/DialogPrimitive.svelte +1 -5
  47. package/esm/ui/dialog/DialogPrimitive.svelte.d.ts +3 -3
  48. package/esm/ui/dialog/dialog.d.ts +10 -8
  49. package/esm/ui/dialog/dialog.js +9 -10
  50. package/esm/ui/internals/FieldContainer.svelte.d.ts +6 -6
  51. package/esm/ui/internals/Input.svelte +10 -1
  52. package/esm/ui/internals/Input.svelte.d.ts +1 -1
  53. package/esm/ui/internals/Textarea.svelte.d.ts +2 -2
  54. package/esm/ui/internals/select/MultiSelectMelt.svelte.d.ts +4 -4
  55. package/esm/ui/internals/select/SelectMelt.svelte.d.ts +7 -7
  56. package/esm/ui/internals/select/SelectRadio.svelte.d.ts +3 -3
  57. package/esm/ui/link/Link.svelte +1 -1
  58. package/esm/ui/link/Link.svelte.d.ts +2 -2
  59. package/esm/ui/link/LinkPlus.svelte +41 -29
  60. package/esm/ui/link/LinkPlus.svelte.d.ts +2 -2
  61. package/esm/utils/transition.d.ts +0 -1
  62. package/esm/vite/index.js +2 -0
  63. package/package.json +3 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # firstly
2
2
 
3
+ ## 0.0.10
4
+
5
+ ### Patch Changes
6
+
7
+ - [#51](https://github.com/jycouet/firstly/pull/51)
8
+ [`803023a`](https://github.com/jycouet/firstly/commit/803023a6257c0bfb9396bc0a7bd454bd1281e26c)
9
+ Thanks [@jycouet](https://github.com/jycouet)! - prepare 0.0.10
10
+
11
+ ## 0.0.9
12
+
13
+ ### Patch Changes
14
+
15
+ - [#43](https://github.com/jycouet/firstly/pull/43)
16
+ [`46cfc39`](https://github.com/jycouet/firstly/commit/46cfc39090fc448a22c5ca95e45507a31ab8e2e0)
17
+ Thanks [@jycouet](https://github.com/jycouet)! - better enum filter, grid action left/right, bump
18
+ deps, opti session check, action after createOptionWhenNoResult
19
+
3
20
  ## 0.0.8
4
21
 
5
22
  ### Patch Changes
package/esm/BaseEnum.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- import { type IdFilter } from 'remult';
2
1
  import type { FindOptionsBase, Repository } from 'remult';
3
2
  export type FF_Icon = {
4
3
  data?: string | string[];
@@ -15,30 +14,20 @@ export type BaseItem = BaseEnumOptions & {
15
14
  sub?: {
16
15
  captionPre?: string;
17
16
  repo?: Repository<any>;
18
- item?: any;
17
+ items?: any[];
19
18
  };
20
19
  };
21
20
  export type BaseEnumOptions<Entity = any> = {
22
21
  caption?: string;
23
22
  icon?: FF_Icon;
24
- where?: IdFilter<Entity> | FindOptionsBase<Entity>['where'];
23
+ where?: FindOptionsBase<Entity>['where'];
25
24
  class?: string;
26
25
  };
27
26
  export declare class BaseEnum<Entity = any> {
28
27
  id: string;
29
28
  caption?: string;
30
29
  icon?: FF_Icon;
31
- where?: IdFilter<Entity> | FindOptionsBase<Entity>['where'];
30
+ where?: FindOptionsBase<Entity>['where'];
32
31
  class?: string;
33
32
  constructor(_id: string | number, options?: BaseEnumOptions<Entity>);
34
- getWhere: () => this | Entity[] | {
35
- $ne?: Entity | Entity[] | undefined;
36
- '!='?: Entity | Entity[] | undefined;
37
- $in?: Entity[] | undefined;
38
- $nin?: Entity[] | undefined;
39
- } | {
40
- $id: import("remult").ValueFilter<Entity extends {
41
- id?: number | undefined;
42
- } ? number : string>;
43
- } | import("remult").EntityFilter<Entity> | NonNullable<Entity>;
44
33
  }
package/esm/BaseEnum.js CHANGED
@@ -1,4 +1,3 @@
1
- import {} from 'remult';
2
1
  export class BaseEnum {
3
2
  id;
4
3
  caption;
@@ -15,7 +14,4 @@ export class BaseEnum {
15
14
  options.icon.caption = options?.caption;
16
15
  }
17
16
  }
18
- getWhere = () => {
19
- return this.where ? this.where : this;
20
- };
21
17
  }
@@ -1,2 +1,2 @@
1
1
  import { type EntityOptions } from 'remult';
2
- export declare function FF_Entity<entityType>(key: string, options: EntityOptions<entityType extends new (...args: any) => any ? InstanceType<entityType> : entityType>): (target: any, info?: import("remult/src/remult3/remult3").ClassDecoratorContextStub<entityType extends infer T ? T extends entityType ? T extends new (...args: any) => any ? T : never : never : never> | undefined) => any;
2
+ export declare function FF_Entity<entityType>(key: string, options: EntityOptions<entityType extends new (...args: any) => any ? InstanceType<entityType> : entityType>): (target: any, info?: import("remult/src/remult3/remult3").ClassDecoratorContextStub<entityType extends infer T ? T extends entityType ? T extends new (...args: any) => any ? entityType : never : never : never> | undefined) => any;
package/esm/FF_Entity.js CHANGED
@@ -1,4 +1,4 @@
1
- import { Entity } from 'remult';
1
+ import { Entity, isBackend } from 'remult';
2
2
  import { recordDeleted, recordSaved } from './changeLog';
3
3
  const toAllow = (permission) => {
4
4
  if (permission) {
@@ -24,7 +24,9 @@ export function FF_Entity(key, options) {
24
24
  // Don't log changes
25
25
  }
26
26
  else {
27
- await recordSaved(entity, e, options.changeLog);
27
+ if (isBackend()) {
28
+ await recordSaved(entity, e, options.changeLog);
29
+ }
28
30
  }
29
31
  },
30
32
  deleted: async (entity, e) => {
@@ -33,7 +35,9 @@ export function FF_Entity(key, options) {
33
35
  // Don't log changes
34
36
  }
35
37
  else {
36
- await recordDeleted(entity, e, options.changeLog);
38
+ if (isBackend()) {
39
+ await recordDeleted(entity, e, options.changeLog);
40
+ }
37
41
  }
38
42
  },
39
43
  });
package/esm/ROUTES.d.ts CHANGED
@@ -7,7 +7,7 @@ type ParamValue = string | number | undefined;
7
7
  /**
8
8
  * Append search params to a string
9
9
  */
10
- export declare const appendSp: (sp?: Record<string, ParamValue | ParamValue[]>, prefix?: '?' | '&') => string;
10
+ export declare const appendSp: (sp?: Record<string, ParamValue | ParamValue[]>, prefix?: "?" | "&") => string;
11
11
  /**
12
12
  * get the current search params
13
13
  *
@@ -41,7 +41,7 @@ declare const AllObjs: {
41
41
  };
42
42
  type AllTypes = typeof AllObjs;
43
43
  export type Routes = keyof AllTypes extends `${string}/${infer Route}` ? `/${Route}` : keyof AllTypes;
44
- export declare const routes: ("/" | "/auth" | "/mail" | "/ui/dialog" | "/ui/enum" | "/ui/fieldGroup" | "/ui/select" | "firstly_sign_in" | "remult_admin" | "github")[];
44
+ export declare const routes: Routes[];
45
45
  /**
46
46
  * To be used like this:
47
47
  * ```ts
@@ -1,5 +1,4 @@
1
- /// <reference types=".pnpm/@sveltejs+kit@2.5.24_@sveltejs+vite-plugin-svelte@3.1.2_svelte@4.2.18_vite@5.4.1_@types+node@_lnml5jetshdinsnlj53joqxhde/node_modules/@sveltejs/kit" />
2
- import { type Handle, type MaybePromise, type RequestEvent } from '@sveltejs/kit';
1
+ import type { Handle, RequestEvent } from '@sveltejs/kit';
3
2
  import { type ClassType } from 'remult';
4
3
  import type { RemultServerOptions } from 'remult/server';
5
4
  import { type MailOptions } from '../mail';
@@ -15,7 +14,7 @@ export type Module = {
15
14
  initRequest?: RemultServerOptions<RequestEvent>['initRequest'];
16
15
  handlePreRemult?: Handle;
17
16
  handlePosRemult?: Handle;
18
- earlyReturn?: (input: Parameters<Handle>[0]) => MaybePromise<{
17
+ earlyReturn?: (input: Parameters<Handle>[0]) => Promise<{
19
18
  early: false;
20
19
  resolve?: undefined;
21
20
  } | {
package/esm/api/index.js CHANGED
@@ -1,4 +1,3 @@
1
- import {} from '@sveltejs/kit';
2
1
  import nodemailer from 'nodemailer';
3
2
  import { remult } from 'remult';
4
3
  import { remultSveltekit } from 'remult/remult-sveltekit';
@@ -23,9 +22,10 @@ export const firstly = (o) => {
23
22
  error: o.error
24
23
  ? o.error
25
24
  : async (e) => {
26
- // if 500 we move to 501 to avoid the default retry mechanism
27
- if (e.httpStatusCode == 500) {
28
- e.sendError(501, e.responseBody);
25
+ // REMULT P2: validation error should probably be 409
26
+ // if 400 we move to 409
27
+ if (e.httpStatusCode == 400) {
28
+ e.sendError(409, e.responseBody);
29
29
  }
30
30
  },
31
31
  // Add user configuration
@@ -9,4 +9,4 @@ export declare const mergeRoles: (existing: string[], newOnes: string[] | undefi
9
9
  roles: string[];
10
10
  changed: boolean;
11
11
  };
12
- export declare const initRoleFromEnv: (log: Log, userEntity: ClassType<FFAuthUser>, envValue: string | undefined, role: string) => Promise<void>;
12
+ export declare const initRoleFromEnv: (log: Log, userEntity: ClassType<FFAuthUser>, envKey: string, role: string) => Promise<void>;
@@ -1,5 +1,6 @@
1
1
  import { repo } from 'remult';
2
2
  import { cyan, green, Log, yellow } from '@kitql/helpers';
3
+ import { env } from '$env/dynamic/private';
3
4
  import { FFAuthUser } from './client/Entities';
4
5
  /**
5
6
  * will merge the roles and remove duplicates
@@ -16,7 +17,8 @@ export const mergeRoles = (existing, newOnes) => {
16
17
  }
17
18
  return { roles: Array.from(result), changed };
18
19
  };
19
- export const initRoleFromEnv = async (log, userEntity, envValue, role) => {
20
+ export const initRoleFromEnv = async (log, userEntity, envKey, role) => {
21
+ const envValue = envKey ? env[envKey] : '';
20
22
  const identifiers = envValue === undefined ? [] : (envValue ?? '').split(',').map((c) => c.trim());
21
23
  for (let i = 0; i < identifiers.length; i++) {
22
24
  const identifier = identifiers[i].trim();
@@ -35,9 +37,9 @@ export const initRoleFromEnv = async (log, userEntity, envValue, role) => {
35
37
  }
36
38
  }
37
39
  if (identifiers.length > 0) {
38
- log.info(`${cyan(role)}: ${identifiers.map((c) => green(c.trim())).join(', ')} added via ${yellow(`.env`)}.`);
40
+ log.info(`${cyan(envKey)}: ${identifiers.map((c) => green(c.trim())).join(', ')} added via ${yellow(`.env`)}.`);
39
41
  }
40
42
  else {
41
- log.info(`${cyan(role)}: No users added via ${yellow(`.env`)}.`);
43
+ log.info(`${cyan(envKey)}: No users added via ${yellow(`.env`)}.`);
42
44
  }
43
45
  };
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { BackendMethod } from 'remult';
7
+ import { Allow, BackendMethod } from 'remult';
8
8
  export class Auth {
9
9
  // Do not show for firstly users ?
10
10
  /** DO NOT USE */
@@ -104,7 +104,7 @@ __decorate([
104
104
  BackendMethod({ allowed: true })
105
105
  ], Auth, "signInDemo", null);
106
106
  __decorate([
107
- BackendMethod({ allowed: true })
107
+ BackendMethod({ allowed: Allow.authenticated })
108
108
  ], Auth, "invite", null);
109
109
  __decorate([
110
110
  BackendMethod({ allowed: true })
@@ -1,7 +1,7 @@
1
1
  import { BaseEnum } from '../..';
2
2
  import type { BaseEnumOptions } from '../..';
3
- export declare const FF_Auth_Role: {
4
- readonly Admin: "FF_Auth_Role.Admin";
3
+ export declare const FF_Role_Auth: {
4
+ readonly Admin: "FF_Role_Auth.Admin";
5
5
  };
6
6
  export declare class FFAuthUser {
7
7
  id: string;
@@ -7,8 +7,8 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var FFAuthProvider_1;
8
8
  import { Fields, Relations, Validators, ValueListFieldType } from 'remult';
9
9
  import { BaseEnum, FF_Entity, FF_Role } from '../..';
10
- export const FF_Auth_Role = {
11
- Admin: 'FF_Auth_Role.Admin',
10
+ export const FF_Role_Auth = {
11
+ Admin: 'FF_Role_Auth.Admin',
12
12
  };
13
13
  let FFAuthUser = class FFAuthUser {
14
14
  id;
@@ -65,7 +65,7 @@ __decorate([
65
65
  ], FFAuthUser.prototype, "sessions", void 0);
66
66
  FFAuthUser = __decorate([
67
67
  FF_Entity('ff_auth.users', {
68
- allowApiCrud: [FF_Auth_Role.Admin, FF_Role.Admin],
68
+ allowApiCrud: [FF_Role_Auth.Admin, FF_Role.Admin],
69
69
  caption: 'FF Auth - Users',
70
70
  })
71
71
  ], FFAuthUser);
@@ -118,7 +118,7 @@ __decorate([
118
118
  ], FFAuthAccount.prototype, "lastVerifiedAt", void 0);
119
119
  FFAuthAccount = __decorate([
120
120
  FF_Entity('ff_auth.accounts', {
121
- allowApiCrud: [FF_Auth_Role.Admin, FF_Role.Admin],
121
+ allowApiCrud: [FF_Role_Auth.Admin, FF_Role.Admin],
122
122
  caption: 'FF Auth - Accounts',
123
123
  // id: { provider: true, userId: true },
124
124
  changeLog: {
@@ -149,7 +149,7 @@ __decorate([
149
149
  ], FFAuthUserSession.prototype, "user", void 0);
150
150
  FFAuthUserSession = __decorate([
151
151
  FF_Entity('ff_auth.users_sessions', {
152
- allowApiCrud: [FF_Auth_Role.Admin, FF_Role.Admin],
152
+ allowApiCrud: [FF_Role_Auth.Admin, FF_Role.Admin],
153
153
  caption: 'FF Auth - Users sessions',
154
154
  changeLog: false,
155
155
  })
@@ -2,6 +2,6 @@ import { Log } from '@kitql/helpers';
2
2
  import { Auth } from './Auth';
3
3
  import { FFAuthAccount, FFAuthProvider, FFAuthUser, FFAuthUserSession } from './Entities';
4
4
  export declare const logAuth: Log;
5
- export { FF_Auth_Role } from './Entities';
5
+ export { FF_Role_Auth } from './Entities';
6
6
  export { Auth };
7
7
  export { FFAuthUser, FFAuthAccount, FFAuthProvider, FFAuthUserSession };
@@ -2,6 +2,6 @@ import { Log } from '@kitql/helpers';
2
2
  import { Auth } from './Auth';
3
3
  import { FFAuthAccount, FFAuthProvider, FFAuthUser, FFAuthUserSession } from './Entities';
4
4
  export const logAuth = new Log('firstly | auth');
5
- export { FF_Auth_Role } from './Entities';
5
+ export { FF_Role_Auth } from './Entities';
6
6
  export { Auth };
7
7
  export { FFAuthUser, FFAuthAccount, FFAuthProvider, FFAuthUserSession };
@@ -4,6 +4,7 @@ import type { ClassType, UserInfo } from 'remult';
4
4
  import type { Module } from '../api';
5
5
  import type { RecursivePartial, ResolvedType } from '../utils/types';
6
6
  import { FFAuthAccount, FFAuthUser, FFAuthUserSession } from './client/Entities';
7
+ import { initRoleFromEnv } from './RoleHelpers';
7
8
  import type { firstlyData, firstlyDataAuth } from './types';
8
9
  export type { firstlyData };
9
10
  export type AuthorizationURLOptions = Record<string, {
@@ -129,6 +130,7 @@ export declare const getSafeOptions: () => {
129
130
  * _Info: index: -777_
130
131
  */
131
132
  export declare const auth: (o: AuthOptions) => Module;
133
+ export { initRoleFromEnv };
132
134
  export declare let lucia: Lucia<Record<any, any>, UserInfo>;
133
135
  declare module 'lucia' {
134
136
  interface Register {
package/esm/auth/index.js CHANGED
@@ -4,12 +4,11 @@ import { Lucia, TimeSpan } from 'lucia';
4
4
  import { remult } from 'remult';
5
5
  import { red } from '@kitql/helpers';
6
6
  import { getRelativePackagePath, read } from '@kitql/internals';
7
- import { env } from '$env/dynamic/private';
8
7
  import { FF_Role } from '../';
9
8
  import { RemultLuciaAdapter } from './Adapter';
10
9
  import { AuthControllerServer } from './AuthController.server';
11
10
  import { Auth, logAuth } from './client';
12
- import { FF_Auth_Role, FFAuthAccount, FFAuthProvider, FFAuthUser, FFAuthUserSession, } from './client/Entities';
11
+ import { FF_Role_Auth, FFAuthAccount, FFAuthProvider, FFAuthUser, FFAuthUserSession, } from './client/Entities';
13
12
  import { createOrExtendSession } from './helper';
14
13
  import { initRoleFromEnv } from './RoleHelpers';
15
14
  export let AUTH_OPTIONS = { ui: {} };
@@ -24,7 +23,7 @@ const buildUrlOrDefault = (base, userSetting, fallback) => {
24
23
  };
25
24
  export const getSafeOptions = () => {
26
25
  const signUp = AUTH_OPTIONS.signUp ?? true;
27
- const base = AUTH_OPTIONS.ui === false ? 'NO_BASE_PATH' : AUTH_OPTIONS.ui?.paths?.base ?? '/ff/auth';
26
+ const base = AUTH_OPTIONS.ui === false ? 'NO_BASE_PATH' : (AUTH_OPTIONS.ui?.paths?.base ?? '/ff/auth');
28
27
  const firstlyData = {
29
28
  module: 'auth',
30
29
  debug: AUTH_OPTIONS.debug,
@@ -150,14 +149,25 @@ export const auth = (o) => {
150
149
  entities: [oSafe.User, oSafe.Session, oSafe.Account],
151
150
  controllers: [Auth],
152
151
  initRequest: async (event) => {
153
- // std session
154
- const sessionId = event.cookies.get(lucia.sessionCookieName);
155
- if (sessionId) {
156
- const { session, user } = await lucia.validateSession(sessionId);
157
- if (session && session.fresh) {
158
- await createOrExtendSession(session.id, session);
152
+ // REMULT: storing user in local should probably be done in remult directly
153
+ if (event?.locals?.user) {
154
+ // console.log('initRequest OK')
155
+ remult.user = event.locals.user;
156
+ }
157
+ else {
158
+ // console.log('initRequest WORK...')
159
+ // std session
160
+ const sessionId = event.cookies.get(lucia.sessionCookieName);
161
+ if (sessionId) {
162
+ const { session, user } = await lucia.validateSession(sessionId);
163
+ if (session && session.fresh) {
164
+ await createOrExtendSession(session.id, session);
165
+ }
166
+ remult.user = user ?? undefined;
167
+ if (event.locals) {
168
+ event.locals.user = user ?? undefined;
169
+ }
159
170
  }
160
- remult.user = user ?? undefined;
161
171
  }
162
172
  },
163
173
  earlyReturn: async ({ event, resolve }) => {
@@ -296,10 +306,11 @@ export const auth = (o) => {
296
306
  return { early: false };
297
307
  },
298
308
  initApi: async () => {
299
- await initRoleFromEnv(logAuth, oSafe.User, env.FF_ADMIN, FF_Role.Admin);
300
- await initRoleFromEnv(logAuth, oSafe.User, env.FF_AUTH_ADMIN, FF_Auth_Role.Admin);
309
+ await initRoleFromEnv(logAuth, oSafe.User, 'FF_ROLE_ADMIN', FF_Role.Admin);
310
+ await initRoleFromEnv(logAuth, oSafe.User, 'FF_ROLE_AUTH_ADMIN', FF_Role_Auth.Admin);
301
311
  },
302
312
  };
303
313
  };
314
+ export { initRoleFromEnv };
304
315
  // Maybe moving this to /auth/server.ts would be better, people will be able to import from firstly all the time
305
316
  export let lucia;
@@ -1,10 +1,10 @@
1
1
  import type { SvelteComponent } from 'svelte';
2
- import { type EntityFilter, type FieldMetadata, type Repository } from 'remult';
2
+ import { type ClassType, type EntityFilter, type FieldMetadata, type Repository } from 'remult';
3
3
  import type { UnArray } from './utils/types.js';
4
4
  export type VisibilityMode = 'view' | 'edit' | 'hide';
5
5
  type CellInternal<Entity> = {
6
6
  col?: keyof Entity;
7
- kind?: 'field' | 'field_link' | 'entity_link' | 'slot' | 'header' | 'component';
7
+ kind?: 'field' | 'field_link' | 'entity_link' | 'slot' | 'header' | 'component' | 'baseItem';
8
8
  class?: string;
9
9
  header?: string;
10
10
  headerSlot?: boolean;
@@ -40,7 +40,7 @@ export declare function cellsBuildor<Entity>(repo: Repository<Entity>, inputBuil
40
40
  export declare function cellBuildor<Entity>(repo: Repository<Entity>, inputBuildor: UnArray<CellsInput<Entity>>): Cell<Entity>;
41
41
  export declare const fieldsOf: <Entity>(b: Cell<Entity>[]) => FieldMetadata<any, Entity>[];
42
42
  export declare const getPlaceholder: <Entity>(fields: FieldMetadata<any, Entity>[]) => string;
43
- export declare const buildSearchWhere: <Entity>(entity: Entity | undefined, fields: FieldMetadata<any, Entity>[], search?: string | null) => EntityFilter<Entity>[];
43
+ export declare const buildSearchWhere: <Entity>(entity: ClassType<Entity> | undefined, fields: FieldMetadata<any, Entity>[], search?: string | null) => EntityFilter<Entity>[];
44
44
  export declare const containsWords: <Entity>(fields: FieldMetadata<any, Entity>[], search: string) => EntityFilter<Entity>;
45
- export declare const buildWhere: <Entity>(entity: Entity | undefined, defaultWhere: EntityFilter<Entity> | undefined, fields_filter: FieldMetadata<any, Entity>[], fields_search: FieldMetadata<any, Entity>[], obj: Record<string, string>) => EntityFilter<Entity>;
45
+ export declare const buildWhere: <Entity>(entity: ClassType<Entity> | undefined, defaultWhere: EntityFilter<Entity> | undefined, fields_filter: FieldMetadata<any, Entity>[], fields_search: FieldMetadata<any, Entity>[], obj: Record<string, string>) => EntityFilter<Entity>;
46
46
  export {};
@@ -77,7 +77,7 @@ export const buildSearchWhere = (entity, fields, search) => {
77
77
  return f;
78
78
  };
79
79
  export const containsWords = (fields, search) => {
80
- const sSplitted = search.split(' ');
80
+ const sSplitted = search.split(' ').filter((s) => s.length > 0);
81
81
  if (fields.length === 1) {
82
82
  return {
83
83
  $and: sSplitted.map((s) => ({ [fields[0].key]: { $contains: s } })),
@@ -106,12 +106,25 @@ export const buildWhere = (entity, defaultWhere, fields_filter, fields_search, o
106
106
  and.push({ [field.key]: obj[field.key] });
107
107
  }
108
108
  else if (field.inputType === 'selectEnum') {
109
+ const fnName = field.key + 'Filter';
109
110
  // @ts-ignore
110
- const theEnum = getEnum(field, obj[field.key]);
111
- // Take the where of the enum if it exists, or it's using this selection as a filter
112
- const wheretoUse = theEnum?.where ?? new BaseEnum(obj[field.key]);
113
- // @ts-ignore
114
- and.push({ [field.key]: wheretoUse });
111
+ if (entity && entity[fnName]) {
112
+ // @ts-ignore
113
+ and.push(entity[fnName](obj[field.key]));
114
+ }
115
+ else {
116
+ // @ts-ignore
117
+ const theEnum = getEnum(field, obj[field.key]);
118
+ // Take the where of the enum if it exists, or it's using this selection as a filter
119
+ if (theEnum?.where) {
120
+ and.push(theEnum.where);
121
+ }
122
+ else {
123
+ const wheretoUse = theEnum?.where ?? new BaseEnum(obj[field.key]);
124
+ // @ts-ignore
125
+ and.push({ [field.key]: wheretoUse });
126
+ }
127
+ }
115
128
  }
116
129
  else if (rfi?.type === 'toOne') {
117
130
  // @ts-ignore (setting the id of the relation)
@@ -16,7 +16,7 @@ export declare class FeedbackController {
16
16
  state: any;
17
17
  items: {
18
18
  bodyHTML: string;
19
- who?: string | undefined;
19
+ who?: string;
20
20
  createdAt: Date;
21
21
  public: boolean;
22
22
  }[];
@@ -21,13 +21,11 @@ async function getGitHub(query, variables) {
21
21
  const response = await fetch(GITHUB_GRAPHQL_ENDPOINT, { method: 'POST', headers, body });
22
22
  const result = await response.json();
23
23
  if (result.errors) {
24
- /* eslint-disable */
25
24
  console.error(`result ERRORS`, body, stry(result));
26
25
  }
27
26
  return result.data;
28
27
  }
29
28
  catch (error) {
30
- /* eslint-disable */
31
29
  console.error(`error`, error);
32
30
  }
33
31
  return null;
@@ -83,11 +83,11 @@ const disableButton = (issueNumber2, title2, content2) => {
83
83
  ).toLocaleTimeString()}</time
84
84
  >
85
85
  </div>
86
- <div class="chat-bubble">{@html item.bodyHTML}</div>
86
+ <div class="chat-bubble prose">{@html item.bodyHTML}</div>
87
87
  <!-- <div class="chat-footer opacity-50">Delivered</div> -->
88
88
  </div>
89
89
  {/each}
90
- {#if issue?.highlight}
90
+ {#if issue?.highlight && issue.state === 'OPEN'}
91
91
  <span class="badge badge-warning">En attente de réponse de TA part 😉, oui 🫵!</span>
92
92
  {/if}
93
93
  {#if issueNumber}
@@ -106,15 +106,15 @@ const disableButton = (issueNumber2, title2, content2) => {
106
106
  ></Textarea>
107
107
  <div class="flex justify-between">
108
108
  {#if issueNumber}
109
- <Button on:click={close} tabIndex={-1} class="btn-outline btn-error">
110
- Clore le feedback
111
- </Button>
109
+ <Button on:click={close} tabIndex={-1} class="btn-outline btn-error"
110
+ >Clore le feedback</Button
111
+ >
112
112
  {:else}
113
113
  <div></div>
114
114
  {/if}
115
- <Button on:click={send} disabled={disableButton(issueNumber, title, content)}>
116
- Envoyer
117
- </Button>
115
+ <Button on:click={send} disabled={disableButton(issueNumber, title, content)}
116
+ >Envoyer</Button
117
+ >
118
118
  </div>
119
119
  {/if}
120
120
  {/if}
@@ -1,4 +1,3 @@
1
- /// <reference types=".pnpm/@sveltejs+kit@2.5.24_@sveltejs+vite-plugin-svelte@3.1.2_svelte@4.2.18_vite@5.4.1_@types+node@_lnml5jetshdinsnlj53joqxhde/node_modules/@sveltejs/kit" />
2
1
  import type { Handle } from '@sveltejs/kit';
3
2
  import type { RemultSveltekitServer } from 'remult/remult-sveltekit';
4
3
  import type { Module } from '../api';
package/esm/helper.d.ts CHANGED
@@ -1,19 +1,9 @@
1
- import type { ClassType, ErrorInfo, FieldMetadata, Repository } from 'remult';
1
+ import type { ClassType, ErrorInfo, FieldMetadata, LifecycleEvent, Repository } from 'remult';
2
2
  import type { BaseEnum, BaseItem } from './index.js';
3
3
  export declare function isError<T>(object: any): object is ErrorInfo<T>;
4
4
  export declare const getFirstInterestingField: <Entity>(repo: Repository<Entity>) => FieldMetadata<any, Entity>;
5
5
  export declare const getEntityDisplayValue: <Entity>(repo: Repository<Entity>, row: Entity) => BaseItem;
6
- export declare const getFieldLinkDisplayValue: (field: FieldMetadata, row: any) => import("./BaseEnum.js").BaseEnumOptions<any> & {
7
- id: string;
8
- captionSub?: string | (string | undefined)[] | undefined;
9
- href?: string | undefined;
10
- repo?: Repository<any> | undefined;
11
- sub?: {
12
- captionPre?: string | undefined;
13
- repo?: Repository<any> | undefined;
14
- item?: any;
15
- } | undefined;
16
- } & {
6
+ export declare const getFieldLinkDisplayValue: (field: FieldMetadata, row: any) => BaseItem & {
17
7
  href: string;
18
8
  };
19
9
  export declare const getEntityDisplayValueFromField: (field: FieldMetadata, row: any) => BaseItem & {
@@ -43,6 +33,18 @@ type MetaTypeSlot = {
43
33
  export type FieldMetaType = MetaTypeRelation | MetaTypeEnum | MetaTypePrimitive | MetaTypeSlot;
44
34
  export declare const getFieldMetaType: (field?: FieldMetadata) => FieldMetaType;
45
35
  export declare const displayWithDefaultAndSuffix: (field: FieldMetadata<any, any> | undefined, value: any) => string;
46
- export declare const getEnum: <T extends BaseEnum<any>>(baseEnum: ClassType<T>, id: string | undefined | null) => T | undefined;
47
- export declare const getEnums: <T extends BaseEnum<any>>(baseEnum: ClassType<T>) => T[];
36
+ export declare const getEnum: <T extends BaseEnum>(baseEnum: ClassType<T>, id: string | undefined | null) => T | undefined;
37
+ export declare const getEnums: <T extends BaseEnum>(baseEnum: ClassType<T>) => T[];
38
+ export declare const upsert: <Entity>(currentRepo: Repository<Entity>, id: Parameters<typeof currentRepo.findId>[0], entity: Partial<Entity>) => Promise<void>;
39
+ /**
40
+ * To be used like:
41
+ * ```ts
42
+ * \@Entity('tasks', {
43
+ * async deleting(item, e) {
44
+ * await onDelete(item, e, 'prevent')
45
+ * },
46
+ * }
47
+ * ```
48
+ */
49
+ export declare const onDelete: <T>(item: T, e: LifecycleEvent<T>, mode?: "prevent" | "cascade") => Promise<void>;
48
50
  export {};
package/esm/helper.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { getEntityRef, getValueList } from 'remult';
2
2
  import { getRelationFieldInfo } from 'remult/internals';
3
+ import { stryEq } from '@kitql/helpers';
3
4
  import { suffixWithS } from './formats/strings.js';
4
5
  export function isError(object) {
5
6
  return object;
@@ -22,7 +23,8 @@ export const getEntityDisplayValue = (repo, row) => {
22
23
  }
23
24
  const field = getFirstInterestingField(repo);
24
25
  // REMULT P3 JYC: If it's an enum, it's not working...
25
- return { caption: row ? field.displayValue(row) : '-', id: '' };
26
+ // @ts-ignore (added for row?.id)
27
+ return { caption: row ? field.displayValue(row) : '-', id: row?.id ? row.id : '' };
26
28
  };
27
29
  export const getFieldLinkDisplayValue = (field, row) => {
28
30
  const caption = field.displayValue(row);
@@ -89,7 +91,7 @@ export const displayWithDefaultAndSuffix = (field, value) => {
89
91
  }
90
92
  else {
91
93
  // toRet.push(value ?? '-')
92
- toRet.push(field?.displayValue ? field?.displayValue({ [field.key]: value }) : value ?? '-');
94
+ toRet.push(field?.displayValue ? field?.displayValue({ [field.key]: value }) : (value ?? '-'));
93
95
  }
94
96
  if (value === undefined || value === null) {
95
97
  return '';
@@ -117,3 +119,57 @@ export const getEnum = (baseEnum, id) => {
117
119
  export const getEnums = (baseEnum) => {
118
120
  return getValueList(baseEnum) || [];
119
121
  };
122
+ export const upsert = async (currentRepo, id, entity) => {
123
+ const found = await currentRepo.findId(id);
124
+ if (found) {
125
+ // @ts-ignore
126
+ if (!stryEq(found, entity)) {
127
+ // Opti => Sedn only the diff?
128
+ await currentRepo.update(id, entity);
129
+ }
130
+ }
131
+ else {
132
+ await currentRepo.insert(entity);
133
+ }
134
+ };
135
+ /**
136
+ * To be used like:
137
+ * ```ts
138
+ * \@Entity('tasks', {
139
+ * async deleting(item, e) {
140
+ * await onDelete(item, e, 'prevent')
141
+ * },
142
+ * }
143
+ * ```
144
+ */
145
+ export const onDelete = async (item, e, mode = 'prevent') => {
146
+ const toManies = e.repository.fields
147
+ .toArray()
148
+ .map((f) => {
149
+ return {
150
+ f: f,
151
+ fi: getRelationFieldInfo(f),
152
+ };
153
+ })
154
+ .filter((f) => f.fi?.type === 'toMany');
155
+ const checks = await Promise.all(toManies.map(async (f_fi) => {
156
+ // @ts-ignore
157
+ const count = await e.repository.relations(item)[f_fi.f.key].count();
158
+ return { ...f_fi, count };
159
+ }));
160
+ const nonEmptyRelations = checks.filter((check) => check.count > 0);
161
+ if (nonEmptyRelations.length > 0) {
162
+ if (mode === 'prevent') {
163
+ const relationNames = nonEmptyRelations.map((r) => r.f.caption).join(', ');
164
+ throw Error(`Can't with existing: ${relationNames}`);
165
+ }
166
+ else if (mode === 'cascade') {
167
+ nonEmptyRelations.forEach(async (r) => {
168
+ const where = Object.entries(r.fi?.getFields().fields ?? {}).map(([key, value]) => {
169
+ return { [key]: item[value] };
170
+ });
171
+ await r.fi?.toRepo.deleteMany({ where });
172
+ });
173
+ }
174
+ }
175
+ };