firstly 0.0.8 → 0.0.9
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/CHANGELOG.md +9 -0
- package/esm/BaseEnum.d.ts +2 -13
- package/esm/BaseEnum.js +0 -4
- package/esm/api/index.d.ts +2 -2
- package/esm/api/index.js +4 -4
- package/esm/auth/RoleHelpers.d.ts +1 -1
- package/esm/auth/RoleHelpers.js +5 -3
- package/esm/auth/client/Auth.js +2 -2
- package/esm/auth/client/Entities.d.ts +2 -2
- package/esm/auth/client/Entities.js +5 -5
- package/esm/auth/client/index.d.ts +1 -1
- package/esm/auth/client/index.js +1 -1
- package/esm/auth/index.d.ts +2 -0
- package/esm/auth/index.js +23 -12
- package/esm/cellsBuildor.d.ts +4 -4
- package/esm/cellsBuildor.js +19 -6
- package/esm/feedback/FeedbackController.js +0 -2
- package/esm/feedback/ui/DialogIssue.svelte +8 -8
- package/esm/helper.js +3 -2
- package/esm/index.d.ts +6 -1
- package/esm/mail/index.js +15 -10
- package/esm/storeList.d.ts +3 -1
- package/esm/storeList.js +20 -10
- package/esm/ui/Field.svelte +9 -3
- package/esm/ui/FieldGroup.svelte +4 -2
- package/esm/ui/Grid.svelte +90 -20
- package/esm/ui/Grid.svelte.d.ts +1 -0
- package/esm/ui/GridPaginate.svelte +6 -4
- package/esm/ui/dialog/DialogPrimitive.svelte +1 -5
- package/esm/ui/dialog/dialog.d.ts +10 -8
- package/esm/ui/dialog/dialog.js +9 -10
- package/esm/ui/internals/Input.svelte +10 -1
- package/esm/ui/link/LinkPlus.svelte +41 -29
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# firstly
|
|
2
2
|
|
|
3
|
+
## 0.0.9
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#43](https://github.com/jycouet/firstly/pull/43)
|
|
8
|
+
[`46cfc39`](https://github.com/jycouet/firstly/commit/46cfc39090fc448a22c5ca95e45507a31ab8e2e0)
|
|
9
|
+
Thanks [@jycouet](https://github.com/jycouet)! - better enum filter, grid action left/right, bump
|
|
10
|
+
deps, opti session check, action after createOptionWhenNoResult
|
|
11
|
+
|
|
3
12
|
## 0.0.8
|
|
4
13
|
|
|
5
14
|
### 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[];
|
|
@@ -21,24 +20,14 @@ export type BaseItem = BaseEnumOptions & {
|
|
|
21
20
|
export type BaseEnumOptions<Entity = any> = {
|
|
22
21
|
caption?: string;
|
|
23
22
|
icon?: FF_Icon;
|
|
24
|
-
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?:
|
|
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
package/esm/api/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
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 {
|
|
2
|
+
import type { Handle, RequestEvent } from '@sveltejs/kit';
|
|
3
3
|
import { type ClassType } from 'remult';
|
|
4
4
|
import type { RemultServerOptions } from 'remult/server';
|
|
5
5
|
import { type MailOptions } from '../mail';
|
|
@@ -15,7 +15,7 @@ export type Module = {
|
|
|
15
15
|
initRequest?: RemultServerOptions<RequestEvent>['initRequest'];
|
|
16
16
|
handlePreRemult?: Handle;
|
|
17
17
|
handlePosRemult?: Handle;
|
|
18
|
-
earlyReturn?: (input: Parameters<Handle>[0]) =>
|
|
18
|
+
earlyReturn?: (input: Parameters<Handle>[0]) => Promise<{
|
|
19
19
|
early: false;
|
|
20
20
|
resolve?: undefined;
|
|
21
21
|
} | {
|
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
|
-
//
|
|
27
|
-
if
|
|
28
|
-
|
|
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>,
|
|
12
|
+
export declare const initRoleFromEnv: (log: Log, userEntity: ClassType<FFAuthUser>, envKey: string, role: string) => Promise<void>;
|
package/esm/auth/RoleHelpers.js
CHANGED
|
@@ -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,
|
|
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(
|
|
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(
|
|
43
|
+
log.info(`${cyan(envKey)}: No users added via ${yellow(`.env`)}.`);
|
|
42
44
|
}
|
|
43
45
|
};
|
package/esm/auth/client/Auth.js
CHANGED
|
@@ -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:
|
|
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
|
|
4
|
-
readonly 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
|
|
11
|
-
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: [
|
|
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: [
|
|
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: [
|
|
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 {
|
|
5
|
+
export { FF_Role_Auth } from './Entities';
|
|
6
6
|
export { Auth };
|
|
7
7
|
export { FFAuthUser, FFAuthAccount, FFAuthProvider, FFAuthUserSession };
|
package/esm/auth/client/index.js
CHANGED
|
@@ -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 {
|
|
5
|
+
export { FF_Role_Auth } from './Entities';
|
|
6
6
|
export { Auth };
|
|
7
7
|
export { FFAuthUser, FFAuthAccount, FFAuthProvider, FFAuthUserSession };
|
package/esm/auth/index.d.ts
CHANGED
|
@@ -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 {
|
|
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
|
-
//
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
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,
|
|
300
|
-
await initRoleFromEnv(logAuth, oSafe.User,
|
|
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;
|
package/esm/cellsBuildor.d.ts
CHANGED
|
@@ -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 {};
|
package/esm/cellsBuildor.js
CHANGED
|
@@ -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
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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)
|
|
@@ -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
|
-
|
|
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
|
-
|
|
115
|
+
<Button on:click={send} disabled={disableButton(issueNumber, title, content)}
|
|
116
|
+
>Envoyer</Button
|
|
117
|
+
>
|
|
118
118
|
</div>
|
|
119
119
|
{/if}
|
|
120
120
|
{/if}
|
package/esm/helper.js
CHANGED
|
@@ -22,7 +22,8 @@ export const getEntityDisplayValue = (repo, row) => {
|
|
|
22
22
|
}
|
|
23
23
|
const field = getFirstInterestingField(repo);
|
|
24
24
|
// REMULT P3 JYC: If it's an enum, it's not working...
|
|
25
|
-
|
|
25
|
+
// @ts-ignore (added for row?.id)
|
|
26
|
+
return { caption: row ? field.displayValue(row) : '-', id: row?.id ? row.id : '' };
|
|
26
27
|
};
|
|
27
28
|
export const getFieldLinkDisplayValue = (field, row) => {
|
|
28
29
|
const caption = field.displayValue(row);
|
|
@@ -89,7 +90,7 @@ export const displayWithDefaultAndSuffix = (field, value) => {
|
|
|
89
90
|
}
|
|
90
91
|
else {
|
|
91
92
|
// toRet.push(value ?? '-')
|
|
92
|
-
toRet.push(field?.displayValue ? field?.displayValue({ [field.key]: value }) : value ?? '-');
|
|
93
|
+
toRet.push(field?.displayValue ? field?.displayValue({ [field.key]: value }) : (value ?? '-'));
|
|
93
94
|
}
|
|
94
95
|
if (value === undefined || value === null) {
|
|
95
96
|
return '';
|
package/esm/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { storeItem } from './storeItem.js';
|
|
|
10
10
|
import { storeList } from './storeList.js';
|
|
11
11
|
import { default as Button } from './ui/Button.svelte';
|
|
12
12
|
import { default as Clipboardable } from './ui/Clipboardable.svelte';
|
|
13
|
+
import type { dialog } from './ui/dialog/dialog.js';
|
|
13
14
|
import { default as DialogManagement } from './ui/dialog/DialogManagement.svelte';
|
|
14
15
|
import { default as FormEditAction } from './ui/dialog/FormEditAction.svelte';
|
|
15
16
|
import { default as Field } from './ui/Field.svelte';
|
|
@@ -72,7 +73,11 @@ declare module 'remult' {
|
|
|
72
73
|
href?: (item: entityType) => string;
|
|
73
74
|
findOptionsForEdit?: ((entity: entityType) => FindOptionsBase<valueType>) | FindOptionsBase<valueType>;
|
|
74
75
|
findOptionsLimit?: number;
|
|
75
|
-
createOptionWhenNoResult?:
|
|
76
|
+
createOptionWhenNoResult?: {
|
|
77
|
+
onCreateRequest: (item: entityType, strCreateNew: string) => Parameters<typeof dialog.form>;
|
|
78
|
+
onSuccess: (entity: entityType, newItem: any) => Promise<void>;
|
|
79
|
+
onError?: () => void;
|
|
80
|
+
};
|
|
76
81
|
multiSelect?: boolean;
|
|
77
82
|
skipForDefaultField?: boolean;
|
|
78
83
|
}
|
package/esm/mail/index.js
CHANGED
|
@@ -14,16 +14,21 @@ export const mailInit = async (nodemailer, o) => {
|
|
|
14
14
|
else {
|
|
15
15
|
try {
|
|
16
16
|
nodemailer.createTestAccount(globalOptions?.apiUrl ?? '', (err, account) => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
17
|
+
if (account) {
|
|
18
|
+
globalOptions = { ...globalOptions, from: account.user };
|
|
19
|
+
transporter = nodemailer.createTransport({
|
|
20
|
+
host: account.smtp.host,
|
|
21
|
+
port: account.smtp.port,
|
|
22
|
+
secure: account.smtp.secure,
|
|
23
|
+
auth: {
|
|
24
|
+
user: account.user,
|
|
25
|
+
pass: account.pass,
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
log.error("Error nodemailer.createTestAccount() can't be done.");
|
|
31
|
+
}
|
|
27
32
|
});
|
|
28
33
|
}
|
|
29
34
|
catch (error) {
|
package/esm/storeList.d.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
/// <reference types="svelte" />
|
|
2
|
-
import type { FindOptions, Repository } from 'remult';
|
|
2
|
+
import type { FindOptions, GroupByOptions, MembersOnly, Repository } from 'remult';
|
|
3
3
|
type TheStoreList<T> = {
|
|
4
4
|
items: T[];
|
|
5
5
|
loading: boolean;
|
|
6
6
|
totalCount: number | undefined;
|
|
7
|
+
agg: any | undefined;
|
|
7
8
|
};
|
|
8
9
|
export type FF_FindOptions<T> = FindOptions<T> & {
|
|
9
10
|
withCount?: boolean;
|
|
10
11
|
withItems?: boolean;
|
|
12
|
+
aggregate?: GroupByOptions<T, (keyof MembersOnly<T>)[], any, any, any, any, any>;
|
|
11
13
|
};
|
|
12
14
|
/**
|
|
13
15
|
* @param repo remult repository to listen to
|
package/esm/storeList.js
CHANGED
|
@@ -15,7 +15,7 @@ import { writable } from 'svelte/store';
|
|
|
15
15
|
* $: browser && tasks.listen(data.options)
|
|
16
16
|
* ```
|
|
17
17
|
*/
|
|
18
|
-
export const storeList = (repo, initValues = { items: [], loading: true, totalCount: undefined }) => {
|
|
18
|
+
export const storeList = (repo, initValues = { items: [], loading: true, totalCount: undefined, agg: undefined }) => {
|
|
19
19
|
const { subscribe, set, update } = writable(initValues);
|
|
20
20
|
let unSub = null;
|
|
21
21
|
onDestroy(async () => {
|
|
@@ -43,27 +43,36 @@ export const storeList = (repo, initValues = { items: [], loading: true, totalCo
|
|
|
43
43
|
throw new Error(`xxx.fetch() withItems and withCount can't be both false!`);
|
|
44
44
|
}
|
|
45
45
|
else if (!withItems && withCount) {
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
let optionsToUse = { where: options?.where };
|
|
47
|
+
if (options?.aggregate) {
|
|
48
|
+
optionsToUse = { ...options.aggregate, where: options?.where };
|
|
49
|
+
}
|
|
50
|
+
// const agg = await repo.aggregate({ ...options?.aggregate, where: options?.where })
|
|
51
|
+
const agg = await repo.aggregate(optionsToUse);
|
|
52
|
+
set({ loading: false, items: [], totalCount: agg.$count, agg });
|
|
48
53
|
if (onNewData) {
|
|
49
|
-
onNewData(undefined,
|
|
54
|
+
onNewData(undefined, agg.$count);
|
|
50
55
|
}
|
|
51
56
|
}
|
|
52
57
|
else if (withItems && !withCount) {
|
|
53
58
|
const items = await repo.find(options);
|
|
54
|
-
set({ loading: false, items, totalCount: undefined });
|
|
59
|
+
set({ loading: false, items, totalCount: undefined, agg: undefined });
|
|
55
60
|
if (onNewData) {
|
|
56
61
|
onNewData(items, undefined);
|
|
57
62
|
}
|
|
58
63
|
}
|
|
59
64
|
else {
|
|
60
|
-
|
|
65
|
+
let optionsToUse = { where: options?.where };
|
|
66
|
+
if (options?.aggregate) {
|
|
67
|
+
optionsToUse = { ...options.aggregate, where: options?.where };
|
|
68
|
+
}
|
|
69
|
+
const [items, agg] = await Promise.all([
|
|
61
70
|
repo.find({ ...options }),
|
|
62
|
-
repo.
|
|
71
|
+
repo.aggregate(optionsToUse),
|
|
63
72
|
]);
|
|
64
|
-
set({ loading: false, items, totalCount });
|
|
73
|
+
set({ loading: false, items, totalCount: agg.$count, agg });
|
|
65
74
|
if (onNewData) {
|
|
66
|
-
onNewData(items,
|
|
75
|
+
onNewData(items, agg.$count);
|
|
67
76
|
}
|
|
68
77
|
}
|
|
69
78
|
}
|
|
@@ -75,7 +84,8 @@ export const storeList = (repo, initValues = { items: [], loading: true, totalCo
|
|
|
75
84
|
const withCount = options?.withCount ?? false;
|
|
76
85
|
let totalCount = undefined;
|
|
77
86
|
if (withCount) {
|
|
78
|
-
|
|
87
|
+
const agg = await repo.aggregate({ where: options?.where });
|
|
88
|
+
totalCount = agg.$count;
|
|
79
89
|
}
|
|
80
90
|
update((c) => {
|
|
81
91
|
return { ...c, items: info.items, loading: false, ...(withCount ? { totalCount } : {}) };
|
package/esm/ui/Field.svelte
CHANGED
|
@@ -101,7 +101,8 @@ const getLoadOptions = async (cellsValues2, str) => {
|
|
|
101
101
|
);
|
|
102
102
|
let totalCount = arr.length;
|
|
103
103
|
if (totalCount === limit) {
|
|
104
|
-
|
|
104
|
+
const agg = await metaTypeObj.repoTarget.aggregate({ where: findToUse.where });
|
|
105
|
+
totalCount = agg.$count;
|
|
105
106
|
}
|
|
106
107
|
if (!cell.field?.options.multiSelect) {
|
|
107
108
|
if (str === "" && getId() && !arr.find((r) => String(r.id) === String(getId()))) {
|
|
@@ -196,7 +197,7 @@ const calcSuffix = (value2) => {
|
|
|
196
197
|
on:issue={(e) => {
|
|
197
198
|
error = e.detail
|
|
198
199
|
}}
|
|
199
|
-
createOptionWhenNoResult={cell.field?.options.createOptionWhenNoResult}
|
|
200
|
+
createOptionWhenNoResult={!!cell.field?.options.createOptionWhenNoResult}
|
|
200
201
|
on:createRequest
|
|
201
202
|
/>
|
|
202
203
|
{/if}
|
|
@@ -237,7 +238,12 @@ const calcSuffix = (value2) => {
|
|
|
237
238
|
type="checkbox"
|
|
238
239
|
{...{ ...common(cell.field), required: undefined }}
|
|
239
240
|
class="checkbox"
|
|
240
|
-
|
|
241
|
+
checked={value}
|
|
242
|
+
on:input={(e) => {
|
|
243
|
+
// @ts-ignore
|
|
244
|
+
value = e.target.checked
|
|
245
|
+
dispatchSelected(value)
|
|
246
|
+
}}
|
|
241
247
|
/>
|
|
242
248
|
</div>
|
|
243
249
|
{:else if metaType.subKind === 'text' || metaType.subKind === 'email' || metaType.subKind === 'password' || metaType.subKind === 'dateOnly' || metaType.subKind === 'number'}
|
package/esm/ui/FieldGroup.svelte
CHANGED
|
@@ -10,9 +10,11 @@ export let store;
|
|
|
10
10
|
export let focusKey = null;
|
|
11
11
|
const getError = (errors, field) => {
|
|
12
12
|
const fo = getRelationFieldInfo(field);
|
|
13
|
-
const keyToUse = fo?.options?.field
|
|
14
|
-
if (errors && errors[keyToUse]) {
|
|
13
|
+
const keyToUse = fo?.options?.field;
|
|
14
|
+
if (errors && keyToUse && errors[keyToUse]) {
|
|
15
15
|
return errors[keyToUse];
|
|
16
|
+
} else if (errors && errors[field.key]) {
|
|
17
|
+
return errors[field.key];
|
|
16
18
|
}
|
|
17
19
|
return void 0;
|
|
18
20
|
};
|
package/esm/ui/Grid.svelte
CHANGED
|
@@ -31,6 +31,7 @@ export let classes = {
|
|
|
31
31
|
};
|
|
32
32
|
export let orderBy = void 0;
|
|
33
33
|
export let orderByCols = void 0;
|
|
34
|
+
export let settingsLeft = false;
|
|
34
35
|
export let dicoNoResult = "Aucun r\xE9sultat !";
|
|
35
36
|
const dispatch = createEventDispatcher();
|
|
36
37
|
const sorting = (toSort, b) => {
|
|
@@ -62,19 +63,55 @@ const sortingIcon = (toSort, b, _orderBy) => {
|
|
|
62
63
|
const cellsToTake = (cells2) => {
|
|
63
64
|
return cells2.filter((c) => c.modeView !== "hide");
|
|
64
65
|
};
|
|
66
|
+
const classForRounding = (i) => {
|
|
67
|
+
if (settingsLeft && (withEdit || withDelete || withAdd)) {
|
|
68
|
+
if (i === 0) {
|
|
69
|
+
return "";
|
|
70
|
+
} else if (i === cells.length - 1) {
|
|
71
|
+
return "rounded-tr-lg";
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (!settingsLeft && (withEdit || withDelete || withAdd)) {
|
|
75
|
+
if (i === 0) {
|
|
76
|
+
return "rounded-tl-lg";
|
|
77
|
+
} else if (i === cells.length - 1) {
|
|
78
|
+
return "";
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (i === 0) {
|
|
82
|
+
return "rounded-tl-lg";
|
|
83
|
+
} else if (i === cells.length - 1) {
|
|
84
|
+
return "rounded-tr-lg";
|
|
85
|
+
}
|
|
86
|
+
};
|
|
65
87
|
</script>
|
|
66
88
|
|
|
67
89
|
<div class="overflow-x-auto">
|
|
68
90
|
<table class="table {classes.table}">
|
|
69
91
|
<thead>
|
|
70
92
|
<tr>
|
|
93
|
+
{#if settingsLeft && (withEdit || withDelete || withAdd)}
|
|
94
|
+
<th class="rounded-tl-lg">
|
|
95
|
+
<div class="flex justify-start">
|
|
96
|
+
{#if !withAdd}
|
|
97
|
+
<Icon data={LibIcon_Settings}></Icon>
|
|
98
|
+
{:else}
|
|
99
|
+
<Button
|
|
100
|
+
permission={store.getRepo().metadata.options.permissionApiInsert}
|
|
101
|
+
disabled={!store.getRepo().metadata.apiInsertAllowed()}
|
|
102
|
+
class="btn btn-square btn-ghost btn-xs"
|
|
103
|
+
on:click={() => dispatch('add', {})}
|
|
104
|
+
>
|
|
105
|
+
<Icon data={LibIcon_Add} />
|
|
106
|
+
</Button>
|
|
107
|
+
{/if}
|
|
108
|
+
</div>
|
|
109
|
+
</th>
|
|
110
|
+
{/if}
|
|
111
|
+
|
|
71
112
|
{#each cellsToTake(cells) as b, i}
|
|
72
113
|
{@const al = align(b.field, b.kind === 'slot')}
|
|
73
|
-
<th
|
|
74
|
-
class="{al}
|
|
75
|
-
{i === 0 ? 'rounded-tl-lg' : ''}
|
|
76
|
-
{i === cells.length - 1 && !withEdit && !withDelete ? 'rounded-tr-lg' : ''}"
|
|
77
|
-
>
|
|
114
|
+
<th class="{al} {classForRounding(i)}">
|
|
78
115
|
{#if b.headerSlot}
|
|
79
116
|
<slot name="header" field={b.field} />
|
|
80
117
|
{:else}
|
|
@@ -98,20 +135,22 @@ const cellsToTake = (cells2) => {
|
|
|
98
135
|
</th>
|
|
99
136
|
{/each}
|
|
100
137
|
|
|
101
|
-
{#if withEdit || withDelete || withAdd}
|
|
102
|
-
<th class="
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
138
|
+
{#if !settingsLeft && (withEdit || withDelete || withAdd)}
|
|
139
|
+
<th class="rounded-tr-lg">
|
|
140
|
+
<div class="flex justify-end">
|
|
141
|
+
{#if withAdd}
|
|
142
|
+
<Button
|
|
143
|
+
permission={store.getRepo().metadata.options.permissionApiInsert}
|
|
144
|
+
disabled={!store.getRepo().metadata.apiInsertAllowed()}
|
|
145
|
+
class="btn btn-square btn-ghost btn-xs"
|
|
146
|
+
on:click={() => dispatch('add', {})}
|
|
147
|
+
>
|
|
148
|
+
<Icon data={LibIcon_Add} />
|
|
149
|
+
</Button>
|
|
150
|
+
{:else}
|
|
151
|
+
<Icon data={LibIcon_Settings}></Icon>
|
|
152
|
+
{/if}
|
|
153
|
+
</div>
|
|
115
154
|
</th>
|
|
116
155
|
{/if}
|
|
117
156
|
</tr>
|
|
@@ -123,6 +162,34 @@ const cellsToTake = (cells2) => {
|
|
|
123
162
|
{:else}
|
|
124
163
|
{#each $store.items as row}
|
|
125
164
|
<tr on:click={() => dispatch('rowclick', row)} class="hover:bg-base-content/20">
|
|
165
|
+
<!-- BECARFULL THIS CODE IS DUPLICATED -->
|
|
166
|
+
{#if settingsLeft && (withEdit || withDelete)}
|
|
167
|
+
<td class="text-left">
|
|
168
|
+
<div class="flex justify-start gap-2">
|
|
169
|
+
{#if withEdit}
|
|
170
|
+
<Button
|
|
171
|
+
permission={store.getRepo().metadata.options.permissionApiUpdate}
|
|
172
|
+
disabled={!store.getRepo().metadata.apiUpdateAllowed()}
|
|
173
|
+
class="btn btn-square btn-ghost btn-xs"
|
|
174
|
+
on:click={() => dispatch('edit', row)}
|
|
175
|
+
>
|
|
176
|
+
<Icon data={LibIcon_Edit} />
|
|
177
|
+
</Button>
|
|
178
|
+
{/if}
|
|
179
|
+
{#if withDelete}
|
|
180
|
+
<Button
|
|
181
|
+
permission={store.getRepo().metadata.options.permissionApiDelete}
|
|
182
|
+
disabled={!store.getRepo().metadata.apiDeleteAllowed()}
|
|
183
|
+
class="btn btn-square btn-ghost btn-xs"
|
|
184
|
+
on:click={() => dispatch('delete', row)}
|
|
185
|
+
>
|
|
186
|
+
<Icon data={LibIcon_Delete} />
|
|
187
|
+
</Button>
|
|
188
|
+
{/if}
|
|
189
|
+
</div>
|
|
190
|
+
</td>
|
|
191
|
+
{/if}
|
|
192
|
+
|
|
126
193
|
{#each cellsToTake(cells) as b}
|
|
127
194
|
{@const metaType = getFieldMetaType(b.field)}
|
|
128
195
|
<td class={align(b.field, b.kind === 'slot')}>
|
|
@@ -153,6 +220,8 @@ const cellsToTake = (cells2) => {
|
|
|
153
220
|
href: b.field?.options?.href ? b.field?.options.href(row) : item?.href,
|
|
154
221
|
}}
|
|
155
222
|
/>
|
|
223
|
+
{:else if b.kind === 'baseItem'}
|
|
224
|
+
<LinkPlus item={row[metaType.field.key]} />
|
|
156
225
|
{:else if b.kind === 'field_link'}
|
|
157
226
|
{@const item = getFieldLinkDisplayValue(metaType.field, row)}
|
|
158
227
|
<LinkPlus {item} />
|
|
@@ -191,7 +260,8 @@ const cellsToTake = (cells2) => {
|
|
|
191
260
|
{/if}
|
|
192
261
|
</td>
|
|
193
262
|
{/each}
|
|
194
|
-
|
|
263
|
+
|
|
264
|
+
{#if !settingsLeft && (withEdit || withDelete)}
|
|
195
265
|
<td class="text-right">
|
|
196
266
|
<div class="flex justify-end gap-2">
|
|
197
267
|
{#if withEdit}
|
package/esm/ui/Grid.svelte.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ declare class __sveltets_Render<T extends Record<any, any>> {
|
|
|
15
15
|
} | undefined;
|
|
16
16
|
orderBy?: EntityOrderBy<T> | undefined;
|
|
17
17
|
orderByCols?: true | (keyof T)[] | undefined;
|
|
18
|
+
settingsLeft?: boolean | undefined;
|
|
18
19
|
dicoNoResult?: string | undefined;
|
|
19
20
|
};
|
|
20
21
|
events(): {
|
|
@@ -24,9 +24,11 @@ $: canGoNext = isValidValue && needPaginate && pageDisplayed < Math.ceil((totalC
|
|
|
24
24
|
</script>
|
|
25
25
|
|
|
26
26
|
<FieldContainer {label} forId="paginate" classes={{ label: 'justify-end' }}>
|
|
27
|
-
<div class="flex items-center justify-end">
|
|
27
|
+
<div class="flex w-36 items-center justify-end">
|
|
28
28
|
{#if totalCount === undefined}
|
|
29
|
-
<Loading class="
|
|
29
|
+
<Loading class="ml-6 mr-2 h-3 w-1/6"></Loading>
|
|
30
|
+
<Loading class="mx-2 h-4 w-1/2"></Loading>
|
|
31
|
+
<Loading class="mx-2 h-3 w-1/6"></Loading>
|
|
30
32
|
{:else if !needPaginate}
|
|
31
33
|
<span class="text-primary justify-end px-2 font-bold">
|
|
32
34
|
{totalCount}
|
|
@@ -36,7 +38,7 @@ $: canGoNext = isValidValue && needPaginate && pageDisplayed < Math.ceil((totalC
|
|
|
36
38
|
<button
|
|
37
39
|
aria-label="left"
|
|
38
40
|
on:click={() => update('-')}
|
|
39
|
-
class="btn join-item {pageDisplayed === 1 ? 'btn-disabled' : ''}"
|
|
41
|
+
class="btn join-item p-1 {pageDisplayed === 1 ? 'btn-disabled' : ''}"
|
|
40
42
|
>
|
|
41
43
|
<Icon data={LibIcon_ChevronLeft} />
|
|
42
44
|
</button>
|
|
@@ -53,7 +55,7 @@ $: canGoNext = isValidValue && needPaginate && pageDisplayed < Math.ceil((totalC
|
|
|
53
55
|
<button
|
|
54
56
|
aria-label="right"
|
|
55
57
|
on:click={() => update('+')}
|
|
56
|
-
class="btn join-item {!canGoNext ? 'btn-disabled' : ''}"
|
|
58
|
+
class="btn join-item p-1 {!canGoNext ? 'btn-disabled' : ''}"
|
|
57
59
|
>
|
|
58
60
|
<Icon data={LibIcon_ChevronRight} />
|
|
59
61
|
</button>
|
|
@@ -40,11 +40,7 @@ function dispatchChange(_data) {
|
|
|
40
40
|
/>
|
|
41
41
|
<div
|
|
42
42
|
class={tw(
|
|
43
|
-
`border-base-content/60
|
|
44
|
-
bg-base-100
|
|
45
|
-
relative z-40 max-h-[90vh] overflow-visible rounded-xl
|
|
46
|
-
border p-6
|
|
47
|
-
shadow-lg`,
|
|
43
|
+
`border-base-content/60 bg-base-100 relative z-40 max-h-[90vh] overflow-visible rounded-xl border p-6 shadow-lg`,
|
|
48
44
|
classes.root,
|
|
49
45
|
)}
|
|
50
46
|
transition:flyAndScale={{
|
|
@@ -29,6 +29,15 @@ type ResultClose<entityType = any> = {
|
|
|
29
29
|
item?: entityType;
|
|
30
30
|
};
|
|
31
31
|
export type DialogType = 'custom' | 'confirm' | 'confirmDelete' | 'insert' | 'update' | 'view';
|
|
32
|
+
export type DialogFormType<entityType> = {
|
|
33
|
+
cells?: CellsInput<entityType>;
|
|
34
|
+
defaults?: Partial<entityType>;
|
|
35
|
+
classes?: DialogClasses;
|
|
36
|
+
noThrow?: boolean;
|
|
37
|
+
wDelete?: boolean;
|
|
38
|
+
topicPrefixText?: string;
|
|
39
|
+
focusKey?: string;
|
|
40
|
+
};
|
|
32
41
|
export type DialogMetaDataInternal<entityType = any> = DialogMetaData<entityType> & {
|
|
33
42
|
id: number;
|
|
34
43
|
type: DialogType;
|
|
@@ -37,14 +46,7 @@ export type DialogMetaDataInternal<entityType = any> = DialogMetaData<entityType
|
|
|
37
46
|
export declare const dialog: {
|
|
38
47
|
confirm: (topic: string, text: string, icon?: string) => Promise<ResultClose<any>>;
|
|
39
48
|
confirmDelete: (topic: string) => Promise<ResultClose<any>>;
|
|
40
|
-
form: <entityType>(type: 'insert' | 'update' | 'view', topic: string, repo: Repository<entityType>,
|
|
41
|
-
defaults?: Partial<entityType>;
|
|
42
|
-
classes?: DialogClasses;
|
|
43
|
-
noThrow?: boolean;
|
|
44
|
-
wDelete?: boolean;
|
|
45
|
-
topicPrefixText?: string;
|
|
46
|
-
focusKey?: string;
|
|
47
|
-
}) => Promise<ResultClose<any>>;
|
|
49
|
+
form: <entityType>(type: 'insert' | 'update' | 'view', topic: string, repo: Repository<entityType>, settings: DialogFormType<entityType>) => Promise<ResultClose<any>>;
|
|
48
50
|
show: (dialog: DialogMetaData) => Promise<ResultClose<any>>;
|
|
49
51
|
close: (id: number, result: ResultClose) => void;
|
|
50
52
|
closeAll: () => void;
|
package/esm/ui/dialog/dialog.js
CHANGED
|
@@ -42,10 +42,9 @@ const createDialogManagement = () => {
|
|
|
42
42
|
};
|
|
43
43
|
return show(detail, 'confirmDelete');
|
|
44
44
|
},
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
? options?.topicPrefixText + ' '
|
|
45
|
+
form: (type, topic, repo, settings) => {
|
|
46
|
+
const topicPrefixText = settings?.topicPrefixText
|
|
47
|
+
? settings?.topicPrefixText + ' '
|
|
49
48
|
: type === 'insert'
|
|
50
49
|
? `Créer `
|
|
51
50
|
: type === 'update'
|
|
@@ -60,12 +59,12 @@ const createDialogManagement = () => {
|
|
|
60
59
|
},
|
|
61
60
|
repo,
|
|
62
61
|
// store,
|
|
63
|
-
cells,
|
|
64
|
-
defaults:
|
|
65
|
-
classes:
|
|
66
|
-
noThrow:
|
|
67
|
-
wDelete:
|
|
68
|
-
focusKey:
|
|
62
|
+
cells: settings.cells ?? [],
|
|
63
|
+
defaults: settings?.defaults,
|
|
64
|
+
classes: settings?.classes,
|
|
65
|
+
noThrow: settings?.noThrow,
|
|
66
|
+
wDelete: settings?.wDelete,
|
|
67
|
+
focusKey: settings?.focusKey,
|
|
69
68
|
topicPrefixText,
|
|
70
69
|
};
|
|
71
70
|
return show(detail, type);
|
|
@@ -20,7 +20,7 @@ const debounce = (fn) => {
|
|
|
20
20
|
};
|
|
21
21
|
function dispatchInput(value2) {
|
|
22
22
|
if ($$restProps.type === "date") {
|
|
23
|
-
if (value2) {
|
|
23
|
+
if (value2 || value2 === null) {
|
|
24
24
|
dispatch("input", { value: transformDate(value2) });
|
|
25
25
|
}
|
|
26
26
|
} else {
|
|
@@ -37,6 +37,12 @@ const handleInput = (e) => {
|
|
|
37
37
|
} else {
|
|
38
38
|
value = target.value.toString().replaceAll(",", ".");
|
|
39
39
|
}
|
|
40
|
+
} else if ($$restProps.type === "date") {
|
|
41
|
+
if (target.value === "") {
|
|
42
|
+
value = null;
|
|
43
|
+
} else {
|
|
44
|
+
value = target.value;
|
|
45
|
+
}
|
|
40
46
|
} else {
|
|
41
47
|
value = target.value;
|
|
42
48
|
}
|
|
@@ -49,6 +55,9 @@ const handleInput = (e) => {
|
|
|
49
55
|
}
|
|
50
56
|
};
|
|
51
57
|
const transformDate = (input) => {
|
|
58
|
+
if (input === null) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
52
61
|
const rawDateSplited = input.split("-");
|
|
53
62
|
if (rawDateSplited.length === 3) {
|
|
54
63
|
const yearSplited = rawDateSplited[0].split("");
|
|
@@ -1,44 +1,56 @@
|
|
|
1
|
-
<script>import {
|
|
1
|
+
<script>import {} from "../..";
|
|
2
2
|
import Icon from "../Icon.svelte";
|
|
3
3
|
import Tooltip from "../Tooltip.svelte";
|
|
4
4
|
import Link from "./Link.svelte";
|
|
5
5
|
export let item;
|
|
6
6
|
export let noIcon = false;
|
|
7
7
|
export let captionSubStyle = "under";
|
|
8
|
+
const hasSomethingToDisplay = (item2) => {
|
|
9
|
+
if (item2.href) {
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
if (item2.caption) {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
return false;
|
|
16
|
+
};
|
|
8
17
|
</script>
|
|
9
18
|
|
|
10
19
|
<div class="flex items-center gap-4">
|
|
11
20
|
{#if item}
|
|
12
21
|
{#if item.icon?.data && !noIcon}
|
|
13
|
-
|
|
14
|
-
<
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
size={item.icon.size}
|
|
18
|
-
/>
|
|
19
|
-
</Tooltip>
|
|
20
|
-
{/if}
|
|
21
|
-
<div class="flex flex-col items-start">
|
|
22
|
-
{#if item.href}
|
|
23
|
-
<div>
|
|
24
|
-
<Link href={item.href}>{item.caption}</Link>
|
|
25
|
-
{#if item.captionSub && captionSubStyle === 'inline'}
|
|
26
|
-
<span class="text-base-content/70 text-xs italic">{item.captionSub}</span>
|
|
27
|
-
{/if}
|
|
28
|
-
</div>
|
|
22
|
+
{#if item.icon.caption}
|
|
23
|
+
<Tooltip text={item.icon.caption}>
|
|
24
|
+
<Icon {...item.icon} />
|
|
25
|
+
</Tooltip>
|
|
29
26
|
{:else}
|
|
30
|
-
|
|
31
|
-
<span
|
|
32
|
-
class="text-base-content {item.class} {(item.caption ?? '').length < 20
|
|
33
|
-
? 'text-nowrap'
|
|
34
|
-
: ''}"
|
|
35
|
-
>
|
|
36
|
-
{item.caption ?? '-'}
|
|
37
|
-
</span>
|
|
38
|
-
{/if}
|
|
39
|
-
{#if item.captionSub && captionSubStyle === 'under'}
|
|
40
|
-
<span class="text-base-content/70 text-xs italic">{item.captionSub}</span>
|
|
27
|
+
<Icon {...item.icon} />
|
|
41
28
|
{/if}
|
|
42
|
-
|
|
29
|
+
{/if}
|
|
30
|
+
|
|
31
|
+
{#if hasSomethingToDisplay(item)}
|
|
32
|
+
<div class="flex flex-col items-start">
|
|
33
|
+
{#if item.href}
|
|
34
|
+
<div>
|
|
35
|
+
<Link href={item.href}>{item.caption}</Link>
|
|
36
|
+
{#if item.captionSub && captionSubStyle === 'inline'}
|
|
37
|
+
<span class="text-base-content/70 text-xs italic">{item.captionSub}</span>
|
|
38
|
+
{/if}
|
|
39
|
+
</div>
|
|
40
|
+
{:else}
|
|
41
|
+
<!-- 20 is a cool value ! -->
|
|
42
|
+
<span
|
|
43
|
+
class="text-base-content {item.class} {(item.caption ?? '').length < 20
|
|
44
|
+
? 'text-nowrap'
|
|
45
|
+
: ''}"
|
|
46
|
+
>
|
|
47
|
+
{item.caption ?? '-'}
|
|
48
|
+
</span>
|
|
49
|
+
{/if}
|
|
50
|
+
{#if item.captionSub && captionSubStyle === 'under'}
|
|
51
|
+
<span class="text-base-content/70 text-xs italic">{item.captionSub}</span>
|
|
52
|
+
{/if}
|
|
53
|
+
</div>
|
|
54
|
+
{/if}
|
|
43
55
|
{/if}
|
|
44
56
|
</div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "firstly",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Firstly, an opinionated Remult setup!",
|
|
6
6
|
"repository": {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
},
|
|
15
15
|
"peerDependencies": {
|
|
16
16
|
"@sveltejs/kit": ">=1.0.0 <3.0.0",
|
|
17
|
-
"remult": "0.27.
|
|
17
|
+
"remult": "0.27.19",
|
|
18
18
|
"svelte": ">=4.2.18"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"arctic": "^1.8.0",
|
|
27
27
|
"clsx": "^2.1.1",
|
|
28
28
|
"cron": "^3.1.7",
|
|
29
|
-
"daisyui": "^4.10
|
|
29
|
+
"daisyui": "^4.12.10",
|
|
30
30
|
"esm-env": "^1.0.0",
|
|
31
31
|
"lucia": "^3.2.0",
|
|
32
32
|
"nodemailer": "^6.9.13",
|