@barcidev/ngx-autogen 0.1.66 → 0.1.67
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/{src/ngrx/store/files/entity/entity.model.ts.template → dist/lib/entity/entity.model.d.ts} +4 -6
- package/dist/lib/entity/entity.model.js +2 -0
- package/dist/lib/entity/index.d.ts +3 -0
- package/dist/lib/entity/index.js +4 -0
- package/dist/lib/entity/with-entity-pagination.d.ts +34 -0
- package/dist/lib/entity/with-entity-pagination.js +47 -0
- package/dist/lib/entity/with-entity-status.d.ts +41 -0
- package/dist/lib/entity/with-entity-status.js +40 -0
- package/package.json +32 -2
- package/src/angular/component/files/__name@dasherize__.component.spec.ts.template +2 -2
- package/src/angular/component/files/__name@dasherize__.component.ts.template +4 -4
- package/src/angular/component/index.js +15 -3
- package/src/angular/component/schema.json +10 -0
- package/src/angular/component/types/types.d.ts +3 -0
- package/src/common/prompts.d.ts +2 -0
- package/src/common/prompts.js +35 -0
- package/src/ngrx/store/files/state/models/__name@dasherize__.model.ts.template +1 -1
- package/src/ngrx/store/files/state/services/__name@dasherize__.service.ts.template +1 -3
- package/src/ngrx/store/files/state/store/__name@dasherize__.store.ts.template +23 -6
- package/src/ngrx/store/index.js +32 -22
- package/src/ngrx/store/schema.json +13 -0
- package/src/ngrx/store/types/types.d.ts +1 -0
- package/src/ngrx/store/files/entity/with-entity-pagination.ts.template +0 -89
- package/src/ngrx/store/files/entity/with-entity-status.ts.template +0 -92
package/{src/ngrx/store/files/entity/entity.model.ts.template → dist/lib/entity/entity.model.d.ts}
RENAMED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { HttpErrorResponse } from '@angular/common/http';
|
|
2
2
|
import { FormControl } from '@angular/forms';
|
|
3
|
-
|
|
4
3
|
export type FormGroupType<T> = {
|
|
5
|
-
|
|
4
|
+
[K in keyof T]: FormControl<T[K]>;
|
|
6
5
|
};
|
|
7
|
-
|
|
8
6
|
export interface RequestConfig<T, U = unknown> {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
onError?: (error?: HttpErrorResponse) => void;
|
|
8
|
+
onSuccess?: (response?: U) => void;
|
|
9
|
+
payload: T;
|
|
12
10
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Signal } from '@angular/core';
|
|
2
|
+
import { EmptyFeatureResult, SignalStoreFeature } from '@ngrx/signals';
|
|
3
|
+
export interface PaginationState {
|
|
4
|
+
page: number;
|
|
5
|
+
pageSize: number;
|
|
6
|
+
totalCount: number;
|
|
7
|
+
}
|
|
8
|
+
interface PaginationComputedProps {
|
|
9
|
+
hasNext: boolean;
|
|
10
|
+
hasPrevious: boolean;
|
|
11
|
+
totalPages: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Resetea el estado de paginación al estado inicial.
|
|
15
|
+
* @returns {PaginationState} - El estado inicial de paginación.
|
|
16
|
+
*/
|
|
17
|
+
export declare function resetPaginationState(): PaginationState;
|
|
18
|
+
/**
|
|
19
|
+
* Agrega funcionalidades de paginación a un Store.
|
|
20
|
+
* @param {[number]} initialPageSize - Tamaño inicial de página (opcional).
|
|
21
|
+
* @returns {SignalStoreFeature} - Características de la tienda con estado, computados y métodos de paginación.
|
|
22
|
+
*/
|
|
23
|
+
export declare function withPagination(initialPageSize?: number): SignalStoreFeature<EmptyFeatureResult, {
|
|
24
|
+
methods: {
|
|
25
|
+
nextPage: () => void;
|
|
26
|
+
previousPage: () => void;
|
|
27
|
+
setPage: (page: number) => void;
|
|
28
|
+
setPageSize: (pageSize: number) => void;
|
|
29
|
+
setTotalCount: (totalCount: number) => void;
|
|
30
|
+
};
|
|
31
|
+
props: Record<'paginationComputed', Signal<PaginationComputedProps>>;
|
|
32
|
+
state: Record<'pagination', PaginationState>;
|
|
33
|
+
}>;
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { computed } from '@angular/core';
|
|
2
|
+
import { patchState, signalStoreFeature, withComputed, withMethods, withState } from '@ngrx/signals';
|
|
3
|
+
const initialPaginationState = {
|
|
4
|
+
page: 1,
|
|
5
|
+
pageSize: 10,
|
|
6
|
+
totalCount: 0
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Resetea el estado de paginación al estado inicial.
|
|
10
|
+
* @returns {PaginationState} - El estado inicial de paginación.
|
|
11
|
+
*/
|
|
12
|
+
export function resetPaginationState() {
|
|
13
|
+
return initialPaginationState;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Agrega funcionalidades de paginación a un Store.
|
|
17
|
+
* @param {[number]} initialPageSize - Tamaño inicial de página (opcional).
|
|
18
|
+
* @returns {SignalStoreFeature} - Características de la tienda con estado, computados y métodos de paginación.
|
|
19
|
+
*/
|
|
20
|
+
export function withPagination(initialPageSize) {
|
|
21
|
+
return signalStoreFeature(withState({
|
|
22
|
+
pagination: initialPageSize ? { ...initialPaginationState, pageSize: initialPageSize } : initialPaginationState
|
|
23
|
+
}), withComputed(({ pagination: { page, pageSize, totalCount } }) => ({
|
|
24
|
+
paginationComputed: computed(() => ({
|
|
25
|
+
hasNext: page() < Math.ceil(totalCount() / pageSize()),
|
|
26
|
+
hasPrevious: page() > 1,
|
|
27
|
+
totalPages: Math.ceil(totalCount() / pageSize())
|
|
28
|
+
}))
|
|
29
|
+
})), withMethods((store) => ({
|
|
30
|
+
nextPage: () => {
|
|
31
|
+
if (store.pagination.page() < Math.ceil(store.pagination.totalCount() / store.pagination.pageSize())) {
|
|
32
|
+
patchState(store, (state) => ({ pagination: { ...state.pagination, page: store.pagination.page() + 1 } }));
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
previousPage: () => {
|
|
36
|
+
if (store.pagination.page() > 1) {
|
|
37
|
+
patchState(store, (state) => ({ pagination: { ...state.pagination, page: store.pagination.page() - 1 } }));
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
setPage: (page) => {
|
|
41
|
+
patchState(store, (state) => ({ pagination: { ...state.pagination, page } }));
|
|
42
|
+
},
|
|
43
|
+
setPageSize: (pageSize) => patchState(store, (state) => ({ pagination: { ...state.pagination, page: 1, pageSize } })), // Reset a pág 1 si cambia el tamaño
|
|
44
|
+
setTotalCount: (totalCount) => patchState(store, (state) => ({ pagination: { ...state.pagination, totalCount } }))
|
|
45
|
+
})));
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=with-entity-pagination.js.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Signal } from '@angular/core';
|
|
2
|
+
import { EntityId } from '@ngrx/signals/entities';
|
|
3
|
+
import { EmptyFeatureResult, SignalStoreFeature } from '@ngrx/signals';
|
|
4
|
+
export interface EntityStatus {
|
|
5
|
+
_removeLoading: boolean;
|
|
6
|
+
_updateLoading: boolean;
|
|
7
|
+
addError: Error | null;
|
|
8
|
+
addLoading: boolean;
|
|
9
|
+
error: Error | null;
|
|
10
|
+
idSelected: EntityId | null;
|
|
11
|
+
idsRemoving: EntityId[];
|
|
12
|
+
idsUpdating: EntityId[];
|
|
13
|
+
loaded: boolean;
|
|
14
|
+
loading: boolean;
|
|
15
|
+
removeError: Error | null;
|
|
16
|
+
selectedError: Error | null;
|
|
17
|
+
selectedLoading: boolean;
|
|
18
|
+
updateError: Error | null;
|
|
19
|
+
}
|
|
20
|
+
interface EntityStatusComputedProps {
|
|
21
|
+
anyError: Error | null;
|
|
22
|
+
isAnyActionLoading: boolean;
|
|
23
|
+
removeLoading: boolean;
|
|
24
|
+
updateLoading: boolean;
|
|
25
|
+
}
|
|
26
|
+
type EntityStatusMethodProps = Record<string, (...args: unknown[]) => unknown>;
|
|
27
|
+
/**
|
|
28
|
+
* Resetea el estado de la entidad al estado inicial.
|
|
29
|
+
* @returns {EntityStatus} - El estado inicial de la entidad.
|
|
30
|
+
*/
|
|
31
|
+
export declare function resetEntityStatus(): EntityStatus;
|
|
32
|
+
/**
|
|
33
|
+
* Agrega funcionalidades comunes de estado y computados para manejar el estado de entidades.
|
|
34
|
+
* @returns {SignalStoreFeature} -Características de la tienda con estado y computados para el manejo de entidades.
|
|
35
|
+
*/
|
|
36
|
+
export declare function withEntityStatus(): SignalStoreFeature<EmptyFeatureResult, {
|
|
37
|
+
methods: EntityStatusMethodProps;
|
|
38
|
+
props: Record<'statusComputed', Signal<EntityStatusComputedProps>>;
|
|
39
|
+
state: Record<'status', EntityStatus>;
|
|
40
|
+
}>;
|
|
41
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { computed } from '@angular/core';
|
|
2
|
+
import { signalStoreFeature, withComputed, withState } from '@ngrx/signals';
|
|
3
|
+
const initialState = {
|
|
4
|
+
_removeLoading: false,
|
|
5
|
+
_updateLoading: false,
|
|
6
|
+
addError: null,
|
|
7
|
+
addLoading: false,
|
|
8
|
+
error: null,
|
|
9
|
+
idSelected: null,
|
|
10
|
+
idsRemoving: [],
|
|
11
|
+
idsUpdating: [],
|
|
12
|
+
loaded: false,
|
|
13
|
+
loading: false,
|
|
14
|
+
removeError: null,
|
|
15
|
+
selectedError: null,
|
|
16
|
+
selectedLoading: false,
|
|
17
|
+
updateError: null
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Resetea el estado de la entidad al estado inicial.
|
|
21
|
+
* @returns {EntityStatus} - El estado inicial de la entidad.
|
|
22
|
+
*/
|
|
23
|
+
export function resetEntityStatus() {
|
|
24
|
+
return initialState;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Agrega funcionalidades comunes de estado y computados para manejar el estado de entidades.
|
|
28
|
+
* @returns {SignalStoreFeature} -Características de la tienda con estado y computados para el manejo de entidades.
|
|
29
|
+
*/
|
|
30
|
+
export function withEntityStatus() {
|
|
31
|
+
return signalStoreFeature(withState({ status: initialState }), withComputed(({ status: { _removeLoading, _updateLoading, addError, error, idsRemoving, idsUpdating, removeError, selectedError, updateError } }) => ({
|
|
32
|
+
statusComputed: computed(() => ({
|
|
33
|
+
anyError: error() || addError() || removeError() || updateError() || selectedError(),
|
|
34
|
+
isAnyActionLoading: idsUpdating().length > 0 || idsRemoving().length > 0,
|
|
35
|
+
removeLoading: _removeLoading() || idsRemoving().length > 0,
|
|
36
|
+
updateLoading: _updateLoading() || idsUpdating().length > 0
|
|
37
|
+
}))
|
|
38
|
+
})));
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=with-entity-status.js.map
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barcidev/ngx-autogen",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.67",
|
|
4
4
|
"description": "A collection of Angular schematics for essential functionalities.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"build": "tsc -p tsconfig.json",
|
|
7
|
+
"build": "tsc -p tsconfig.json && tsc -p tsconfig.lib.json",
|
|
8
8
|
"release": "npm run build && npm publish --access public",
|
|
9
9
|
"test": "npm run build && jasmine src/**/*_spec.js",
|
|
10
10
|
"prepublishOnly": "npm run build"
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
"src/**/*.d.ts",
|
|
16
16
|
"src/**/schema.json",
|
|
17
17
|
"src/collection.json",
|
|
18
|
+
"dist/lib/**/*.js",
|
|
19
|
+
"dist/lib/**/*.d.ts",
|
|
18
20
|
"README.md",
|
|
19
21
|
"LICENSE"
|
|
20
22
|
],
|
|
@@ -56,9 +58,37 @@
|
|
|
56
58
|
},
|
|
57
59
|
"devDependencies": {
|
|
58
60
|
"@angular-devkit/schematics-cli": "^21.2.0",
|
|
61
|
+
"@angular/forms": "^21.2.11",
|
|
62
|
+
"@ngrx/signals": "^21.1.0",
|
|
59
63
|
"@types/jasmine": "~5.1.0",
|
|
60
64
|
"@types/node": "^20.17.19",
|
|
61
65
|
"copyfiles": "^2.4.1",
|
|
62
66
|
"jasmine": "^5.0.0"
|
|
67
|
+
},
|
|
68
|
+
"peerDependencies": {
|
|
69
|
+
"@angular/common": ">=17.0.0",
|
|
70
|
+
"@angular/core": ">=17.0.0",
|
|
71
|
+
"@angular/forms": ">=17.0.0",
|
|
72
|
+
"@ngrx/signals": ">=17.0.0"
|
|
73
|
+
},
|
|
74
|
+
"peerDependenciesMeta": {
|
|
75
|
+
"@angular/common": {
|
|
76
|
+
"optional": true
|
|
77
|
+
},
|
|
78
|
+
"@angular/core": {
|
|
79
|
+
"optional": true
|
|
80
|
+
},
|
|
81
|
+
"@angular/forms": {
|
|
82
|
+
"optional": true
|
|
83
|
+
},
|
|
84
|
+
"@ngrx/signals": {
|
|
85
|
+
"optional": true
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
"exports": {
|
|
89
|
+
"./entity": {
|
|
90
|
+
"types": "./dist/lib/entity/index.d.ts",
|
|
91
|
+
"default": "./dist/lib/entity/index.js"
|
|
92
|
+
}
|
|
63
93
|
}
|
|
64
94
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
2
|
import { <%= classify(name) %>Component } from './<%= dasherize(name) %>.component';
|
|
3
|
-
<% if (store === 'Yes') { %>import { <%= classify(
|
|
3
|
+
<% if (store === 'Yes') { %>import { <%= classify(storeName) %>Store } from './state';<% } %>
|
|
4
4
|
|
|
5
5
|
describe('<%= classify(name) %>Component', () => {
|
|
6
6
|
let component: <%= classify(name) %>Component;
|
|
@@ -10,7 +10,7 @@ describe('<%= classify(name) %>Component', () => {
|
|
|
10
10
|
await TestBed.configureTestingModule({
|
|
11
11
|
imports: [<%= classify(name) %>Component],
|
|
12
12
|
providers: [
|
|
13
|
-
<% if (store === 'Yes') { %><%= classify(
|
|
13
|
+
<% if (store === 'Yes') { %><%= classify(storeName) %>Store,<% } %>
|
|
14
14
|
]
|
|
15
15
|
}).compileComponents();
|
|
16
16
|
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { Component, inject } from '@angular/core';
|
|
2
2
|
<% if (store === 'Yes') { %>
|
|
3
|
-
import { <%= classify(
|
|
3
|
+
import { <%= classify(storeName) %>Store<% if (!isProvideInRoot) { %>, provide<%= classify(storeName) %>Store<% } %> } from './state';
|
|
4
4
|
import { JsonPipe } from '@angular/common';
|
|
5
5
|
<% } %>
|
|
6
6
|
|
|
7
7
|
@Component({
|
|
8
8
|
imports: [<% if (store === 'Yes') { %>JsonPipe<% } %>],
|
|
9
|
-
providers: [],
|
|
9
|
+
providers: [<% if (store === 'Yes' && !isProvideInRoot) { %>...provide<%= classify(storeName) %>Store()<% } %>],
|
|
10
10
|
selector: 'app-<%= dasherize(name) %>',
|
|
11
11
|
styleUrls: ['./<%= dasherize(name) %>.component.css'],
|
|
12
12
|
templateUrl: './<%= dasherize(name) %>.component.html',
|
|
13
13
|
})
|
|
14
14
|
export class <%= classify(name) %>Component {
|
|
15
|
-
<% if (store === 'Yes') { %> private _<%= camelize(
|
|
16
|
-
data$ = this._<%= camelize(
|
|
15
|
+
<% if (store === 'Yes') { %> private _<%= camelize(storeName) %>Store = inject(<%= classify(storeName) %>Store);
|
|
16
|
+
data$ = this._<%= camelize(storeName) %>Store.entities();<% } %>
|
|
17
17
|
}
|
|
@@ -14,12 +14,22 @@ const schematics_1 = require("@angular-devkit/schematics");
|
|
|
14
14
|
const workspace_1 = require("@schematics/angular/utility/workspace");
|
|
15
15
|
const path_1 = require("path");
|
|
16
16
|
const pluralize_1 = require("../../common/pluralize");
|
|
17
|
+
const prompts_1 = require("../../common/prompts");
|
|
17
18
|
function component(options) {
|
|
18
19
|
return (tree) => __awaiter(this, void 0, void 0, function* () {
|
|
19
20
|
const workspace = yield (0, workspace_1.getWorkspace)(tree);
|
|
20
|
-
|
|
21
|
+
if (options.store === "Yes") {
|
|
22
|
+
if (!options.storeName) {
|
|
23
|
+
options.storeName = yield (0, prompts_1.askInput)("What is the name of the entity store to create?", options.name);
|
|
24
|
+
}
|
|
25
|
+
if (!options.pk) {
|
|
26
|
+
options.pk = yield (0, prompts_1.askInput)("What is the name of the default Primary Key (e.g., id, cod, uuid)?", "id");
|
|
27
|
+
}
|
|
28
|
+
if (options.isProvideInRoot === undefined) {
|
|
29
|
+
options.isProvideInRoot = yield (0, prompts_1.askConfirm)("Should the store and service be provided in root?", false);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
21
32
|
const context = resolveComponentContext(workspace, options);
|
|
22
|
-
// Aquí podrías agregar más reglas para otras funcionalidades, como NgRx
|
|
23
33
|
return (0, schematics_1.chain)([
|
|
24
34
|
generateComponentFiles(context),
|
|
25
35
|
options.i18n === "Yes"
|
|
@@ -30,8 +40,10 @@ function component(options) {
|
|
|
30
40
|
: (0, schematics_1.noop)(),
|
|
31
41
|
options.store === "Yes"
|
|
32
42
|
? (0, schematics_1.schematic)("app-store", {
|
|
33
|
-
name: context.options.name,
|
|
43
|
+
name: options.storeName || context.options.name,
|
|
34
44
|
path: (0, path_1.join)(context.movePath, context.nameDash),
|
|
45
|
+
pk: context.options.pk,
|
|
46
|
+
isProvideInRoot: context.options.isProvideInRoot,
|
|
35
47
|
})
|
|
36
48
|
: (0, schematics_1.noop)(),
|
|
37
49
|
]);
|
|
@@ -22,6 +22,16 @@
|
|
|
22
22
|
"x-prompt": "Do you want to create an i18n file for the component?",
|
|
23
23
|
"enum": ["Yes", "No"]
|
|
24
24
|
},
|
|
25
|
+
"pk": {
|
|
26
|
+
"type": "string",
|
|
27
|
+
"description": "The name of the default Primary Key (e.g., id, cod, uuid); default is 'id'.",
|
|
28
|
+
"default": "id"
|
|
29
|
+
},
|
|
30
|
+
"isProvideInRoot": {
|
|
31
|
+
"type": "boolean",
|
|
32
|
+
"description": "Whether the store and service should be provided in root.",
|
|
33
|
+
"default": false
|
|
34
|
+
},
|
|
25
35
|
"path": {
|
|
26
36
|
"type": "string",
|
|
27
37
|
"description": "Destination path."
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.askInput = askInput;
|
|
4
|
+
exports.askConfirm = askConfirm;
|
|
5
|
+
const readline = require("readline");
|
|
6
|
+
function askInput(question, defaultValue) {
|
|
7
|
+
const rl = readline.createInterface({
|
|
8
|
+
input: process.stdin,
|
|
9
|
+
output: process.stdout,
|
|
10
|
+
});
|
|
11
|
+
const suffix = defaultValue ? ` (${defaultValue})` : "";
|
|
12
|
+
return new Promise((resolve) => {
|
|
13
|
+
rl.question(`${question}${suffix}: `, (answer) => {
|
|
14
|
+
rl.close();
|
|
15
|
+
resolve(answer.trim() || defaultValue || "");
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
function askConfirm(question, defaultValue = false) {
|
|
20
|
+
const rl = readline.createInterface({
|
|
21
|
+
input: process.stdin,
|
|
22
|
+
output: process.stdout,
|
|
23
|
+
});
|
|
24
|
+
const hint = defaultValue ? "(Y/n)" : "(y/N)";
|
|
25
|
+
return new Promise((resolve) => {
|
|
26
|
+
rl.question(`${question} ${hint}: `, (answer) => {
|
|
27
|
+
rl.close();
|
|
28
|
+
const normalized = answer.trim().toLowerCase();
|
|
29
|
+
if (normalized === "")
|
|
30
|
+
return resolve(defaultValue);
|
|
31
|
+
resolve(normalized === "y" || normalized === "yes");
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -6,9 +6,7 @@ import {
|
|
|
6
6
|
Update<%= classify(name) %>
|
|
7
7
|
} from '<%= grouped ? "../models/" + dasherize(name) + ".model" : "./" + dasherize(name) + ".model" %>';
|
|
8
8
|
|
|
9
|
-
@Injectable({
|
|
10
|
-
providedIn: 'root'
|
|
11
|
-
})
|
|
9
|
+
@Injectable(<%= isProvideInRoot ? "{ providedIn: 'root' }" : "" %>)
|
|
12
10
|
export class <%= classify(name) %>Service {
|
|
13
11
|
|
|
14
12
|
add<%= classify(name) %>$(payload: Add<%= classify(name) %>): Observable<number> {
|
|
@@ -10,10 +10,9 @@ import {
|
|
|
10
10
|
} from '@ngrx/signals/entities';
|
|
11
11
|
import { rxMethod } from '@ngrx/signals/rxjs-interop';
|
|
12
12
|
import { catchError, EMPTY, pipe, switchMap, tap } from 'rxjs';
|
|
13
|
+
import { EntityId } from '@ngrx/signals/entities';
|
|
13
14
|
|
|
14
|
-
import { RequestConfig } from '@
|
|
15
|
-
import { withPagination } from '@shared-state/with-entity-pagination';
|
|
16
|
-
import { withEntityStatus } from '@shared-state/with-entity-status';
|
|
15
|
+
import { RequestConfig, withEntityStatus, withPagination } from '@barcidev/ngx-autogen/entity';
|
|
17
16
|
import {
|
|
18
17
|
Add<%= classify(name) %>,
|
|
19
18
|
<%= classify(name) %>Dto,
|
|
@@ -27,12 +26,11 @@ const config = entityConfig({
|
|
|
27
26
|
});
|
|
28
27
|
|
|
29
28
|
export const <%= classify(name) %>Store = signalStore(
|
|
30
|
-
{ providedIn: 'root' },
|
|
29
|
+
<%= isProvideInRoot ? "{ providedIn: 'root' }," : "" %>
|
|
31
30
|
withEntities(config),
|
|
32
31
|
withEntityStatus(),
|
|
33
32
|
withPagination(),
|
|
34
33
|
withComputed(({ entities, entityMap, status: { idSelected } }) => ({
|
|
35
|
-
<%= camelize(pluralize(name)) %>: computed(() => entities()),
|
|
36
34
|
<%= camelize(name) %>Seleccionado: computed(() => {
|
|
37
35
|
const <%= pk %> = idSelected();
|
|
38
36
|
return <%= pk %> ? entityMap()[<%= pk %>] : null;
|
|
@@ -142,6 +140,18 @@ export const <%= classify(name) %>Store = signalStore(
|
|
|
142
140
|
})
|
|
143
141
|
)
|
|
144
142
|
),
|
|
143
|
+
select<%= classify(name) %>: rxMethod<EntityId | null>(
|
|
144
|
+
pipe(
|
|
145
|
+
tap((payload) => {
|
|
146
|
+
patchState(store, (state) => ({
|
|
147
|
+
status: {
|
|
148
|
+
...state.status,
|
|
149
|
+
idSelected: payload
|
|
150
|
+
}
|
|
151
|
+
}));
|
|
152
|
+
})
|
|
153
|
+
)
|
|
154
|
+
),
|
|
145
155
|
update<%= classify(name) %>: rxMethod<RequestConfig<Update<%= classify(name) %>, boolean>>(
|
|
146
156
|
pipe(
|
|
147
157
|
tap(({ payload }) => {
|
|
@@ -198,4 +208,11 @@ export const <%= classify(name) %>Store = signalStore(
|
|
|
198
208
|
store.load<%= classify(pluralize(name)) %>();
|
|
199
209
|
},
|
|
200
210
|
})
|
|
201
|
-
);
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
export function provide<%= classify(name) %>Store() {
|
|
214
|
+
return <%= isProvideInRoot ? [
|
|
215
|
+
<%= classify(name) %>Service,
|
|
216
|
+
<%= classify(name) %>Store,
|
|
217
|
+
] : [ <%= classify(name) %>Store ]
|
|
218
|
+
}
|
package/src/ngrx/store/index.js
CHANGED
|
@@ -16,12 +16,13 @@ const tasks_1 = require("@angular-devkit/schematics/tasks");
|
|
|
16
16
|
const dependencies_1 = require("@schematics/angular/utility/dependencies");
|
|
17
17
|
const workspace_1 = require("@schematics/angular/utility/workspace");
|
|
18
18
|
const jsonc_parser_1 = require("jsonc-parser");
|
|
19
|
-
const file_actions_1 = require("../../common/file-actions");
|
|
20
19
|
const pluralize_1 = require("../../common/pluralize");
|
|
21
20
|
const project_metadata_1 = require("../../common/project-metadata");
|
|
22
21
|
const NGRX_SIGNALS = "@ngrx/signals";
|
|
22
|
+
let _needsInstall = false;
|
|
23
23
|
function signalStore(options) {
|
|
24
24
|
return (tree) => __awaiter(this, void 0, void 0, function* () {
|
|
25
|
+
_needsInstall = false;
|
|
25
26
|
const workspace = yield (0, workspace_1.getWorkspace)(tree);
|
|
26
27
|
// 1. Preparar contexto y opciones enriquecidas
|
|
27
28
|
const context = resolveStoreContext(workspace, options);
|
|
@@ -35,12 +36,14 @@ function signalStore(options) {
|
|
|
35
36
|
ensureNgrxSignals(angularVersion),
|
|
36
37
|
updateIndexFile(context),
|
|
37
38
|
generateStoreFiles(context),
|
|
38
|
-
(0, file_actions_1.mergeFilesSmart)("./files/entity", "src/app/shared/state", context.options, tree),
|
|
39
39
|
updateAngularJson(context.options),
|
|
40
40
|
updateTsConfigRule(projectRoot),
|
|
41
|
-
(host,
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
(host, ctx) => {
|
|
42
|
+
if (_needsInstall) {
|
|
43
|
+
ctx.addTask(new tasks_1.NodePackageInstallTask());
|
|
44
|
+
ctx.logger.info("📦 Instalando dependencias...");
|
|
45
|
+
}
|
|
46
|
+
ctx.logger.info("🚀 Entorno preparado con éxito.");
|
|
44
47
|
return host;
|
|
45
48
|
},
|
|
46
49
|
]);
|
|
@@ -85,20 +88,16 @@ function resolveStoreContext(workspace, options) {
|
|
|
85
88
|
*/
|
|
86
89
|
function ensureNgrxSignals(version) {
|
|
87
90
|
return (tree) => {
|
|
88
|
-
// 1. Intentamos obtener la dependencia si ya existe
|
|
89
91
|
const existingDep = (0, dependencies_1.getPackageJsonDependency)(tree, NGRX_SIGNALS);
|
|
90
|
-
|
|
91
|
-
if (existingDep) {
|
|
92
|
-
// Opcional: podrías loguear un mensaje aquí
|
|
92
|
+
if (existingDep)
|
|
93
93
|
return tree;
|
|
94
|
-
}
|
|
95
|
-
// 3. Si no existe, la añadimos
|
|
96
94
|
(0, dependencies_1.addPackageJsonDependency)(tree, {
|
|
97
95
|
type: dependencies_1.NodeDependencyType.Default,
|
|
98
96
|
name: NGRX_SIGNALS,
|
|
99
97
|
version: `^${version}.0.0`,
|
|
100
98
|
overwrite: false,
|
|
101
99
|
});
|
|
100
|
+
_needsInstall = true;
|
|
102
101
|
return tree;
|
|
103
102
|
};
|
|
104
103
|
}
|
|
@@ -147,7 +146,7 @@ function generateStoreFiles(ctx) {
|
|
|
147
146
|
}
|
|
148
147
|
function updateTsConfigRule(root) {
|
|
149
148
|
return (tree, context) => {
|
|
150
|
-
var _a, _b;
|
|
149
|
+
var _a, _b, _c, _d, _e;
|
|
151
150
|
const tsConfigPath = tree.exists("/tsconfig.app.json")
|
|
152
151
|
? "/tsconfig.app.json"
|
|
153
152
|
: "/tsconfig.json";
|
|
@@ -155,21 +154,28 @@ function updateTsConfigRule(root) {
|
|
|
155
154
|
if (!buffer)
|
|
156
155
|
return;
|
|
157
156
|
let content = buffer.toString();
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
// 1. Asegurar baseUrl
|
|
162
|
-
if (!((_a = (0, jsonc_parser_1.parse)(content).compilerOptions) === null || _a === void 0 ? void 0 : _a.baseUrl)) {
|
|
163
|
-
content = (0, jsonc_parser_1.applyEdits)(content, (0, jsonc_parser_1.modify)(content, ["compilerOptions", "baseUrl"], "./", modOptions));
|
|
164
|
-
}
|
|
165
|
-
// 2. Calcular path relativo al baseUrl
|
|
166
|
-
const baseUrl = ((_b = (0, jsonc_parser_1.parse)(content).compilerOptions) === null || _b === void 0 ? void 0 : _b.baseUrl) || "./";
|
|
157
|
+
const parsed = (0, jsonc_parser_1.parse)(content);
|
|
158
|
+
// Calcular el path esperado del alias
|
|
159
|
+
const baseUrl = ((_a = parsed.compilerOptions) === null || _a === void 0 ? void 0 : _a.baseUrl) || "./";
|
|
167
160
|
let i18nPath = `${root}/app/shared/state/*`;
|
|
168
161
|
const normalizedBase = baseUrl.replace(/^\.\/|\/$/g, "");
|
|
169
162
|
if (normalizedBase && i18nPath.startsWith(normalizedBase)) {
|
|
170
163
|
i18nPath = i18nPath.replace(normalizedBase, "").replace(/^\//, "");
|
|
171
164
|
}
|
|
172
|
-
//
|
|
165
|
+
// Verificar si ya tiene baseUrl y el alias correcto
|
|
166
|
+
const existingPaths = (_c = (_b = parsed.compilerOptions) === null || _b === void 0 ? void 0 : _b.paths) === null || _c === void 0 ? void 0 : _c["@shared-state/*"];
|
|
167
|
+
const alreadyConfigured = ((_d = parsed.compilerOptions) === null || _d === void 0 ? void 0 : _d.baseUrl) &&
|
|
168
|
+
Array.isArray(existingPaths) &&
|
|
169
|
+
existingPaths.length === 1 &&
|
|
170
|
+
existingPaths[0] === i18nPath;
|
|
171
|
+
if (alreadyConfigured)
|
|
172
|
+
return;
|
|
173
|
+
const modOptions = {
|
|
174
|
+
formattingOptions: { insertSpaces: true, tabSize: 2 },
|
|
175
|
+
};
|
|
176
|
+
if (!((_e = parsed.compilerOptions) === null || _e === void 0 ? void 0 : _e.baseUrl)) {
|
|
177
|
+
content = (0, jsonc_parser_1.applyEdits)(content, (0, jsonc_parser_1.modify)(content, ["compilerOptions", "baseUrl"], "./", modOptions));
|
|
178
|
+
}
|
|
173
179
|
const finalContent = (0, jsonc_parser_1.applyEdits)(content, (0, jsonc_parser_1.modify)(content, ["compilerOptions", "paths", "@shared-state/*"], [i18nPath], modOptions));
|
|
174
180
|
tree.overwrite(tsConfigPath, finalContent);
|
|
175
181
|
context.logger.info(`✅ Alias @shared-state configurado.`);
|
|
@@ -177,11 +183,15 @@ function updateTsConfigRule(root) {
|
|
|
177
183
|
}
|
|
178
184
|
function updateAngularJson(options) {
|
|
179
185
|
return (tree) => {
|
|
186
|
+
var _a;
|
|
180
187
|
const path = "/angular.json";
|
|
181
188
|
const buffer = tree.read(path);
|
|
182
189
|
if (!buffer)
|
|
183
190
|
return;
|
|
184
191
|
const workspace = JSON.parse(buffer.toString());
|
|
192
|
+
const existing = (_a = workspace.schematics) === null || _a === void 0 ? void 0 : _a["@barcidev/ngx-autogen:signal-state"];
|
|
193
|
+
if ((existing === null || existing === void 0 ? void 0 : existing.pk) === options.pk && (existing === null || existing === void 0 ? void 0 : existing.lang) === options.lang)
|
|
194
|
+
return;
|
|
185
195
|
if (!workspace.schematics)
|
|
186
196
|
workspace.schematics = {};
|
|
187
197
|
workspace.schematics["@barcidev/ngx-autogen:signal-state"] = {
|
|
@@ -28,6 +28,19 @@
|
|
|
28
28
|
"lang":{
|
|
29
29
|
"type": "string",
|
|
30
30
|
"description": "The default language for the application (en, es); default is 'en'."
|
|
31
|
+
},
|
|
32
|
+
"isProvideInRoot": {
|
|
33
|
+
"type": "boolean",
|
|
34
|
+
"description": "Whether the store and service should be provided in root.",
|
|
35
|
+
"default": false,
|
|
36
|
+
"x-prompt": {
|
|
37
|
+
"message": "Should the store and service be provided in root?",
|
|
38
|
+
"type": "list",
|
|
39
|
+
"items": [
|
|
40
|
+
{ "value": true, "label": "Yes" },
|
|
41
|
+
{ "value": false, "label": "No" }
|
|
42
|
+
]
|
|
43
|
+
}
|
|
31
44
|
}
|
|
32
45
|
},
|
|
33
46
|
"required": ["name"]
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { computed, Signal } from '@angular/core';
|
|
2
|
-
import {
|
|
3
|
-
EmptyFeatureResult,
|
|
4
|
-
patchState,
|
|
5
|
-
SignalStoreFeature,
|
|
6
|
-
signalStoreFeature,
|
|
7
|
-
withComputed,
|
|
8
|
-
withMethods,
|
|
9
|
-
withState
|
|
10
|
-
} from '@ngrx/signals';
|
|
11
|
-
|
|
12
|
-
export interface PaginationState {
|
|
13
|
-
page: number;
|
|
14
|
-
pageSize: number;
|
|
15
|
-
totalCount: number;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
interface PaginationComputedProps {
|
|
19
|
-
hasNext: boolean;
|
|
20
|
-
hasPrevious: boolean;
|
|
21
|
-
totalPages: number;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const initialPaginationState: PaginationState = {
|
|
25
|
-
page: 1,
|
|
26
|
-
pageSize: 10,
|
|
27
|
-
totalCount: 0
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Resetea el estado de paginación al estado inicial.
|
|
32
|
-
* @returns {PaginationState} - El estado inicial de paginación.
|
|
33
|
-
*/
|
|
34
|
-
export function resetPaginationState(): PaginationState {
|
|
35
|
-
return initialPaginationState;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Agrega funcionalidades de paginación a un Store.
|
|
40
|
-
* @param {[number]} initialPageSize - Tamaño inicial de página (opcional).
|
|
41
|
-
* @returns {SignalStoreFeature} - Características de la tienda con estado, computados y métodos de paginación.
|
|
42
|
-
*/
|
|
43
|
-
export function withPagination(initialPageSize?: number): SignalStoreFeature<
|
|
44
|
-
EmptyFeatureResult,
|
|
45
|
-
{
|
|
46
|
-
methods: {
|
|
47
|
-
nextPage: () => void;
|
|
48
|
-
previousPage: () => void;
|
|
49
|
-
setPage: (page: number) => void;
|
|
50
|
-
setPageSize: (pageSize: number) => void;
|
|
51
|
-
setTotalCount: (totalCount: number) => void;
|
|
52
|
-
};
|
|
53
|
-
props: Record<'paginationComputed', Signal<PaginationComputedProps>>;
|
|
54
|
-
state: Record<'pagination', PaginationState>;
|
|
55
|
-
}
|
|
56
|
-
> {
|
|
57
|
-
return signalStoreFeature(
|
|
58
|
-
withState({
|
|
59
|
-
pagination: initialPageSize ? { ...initialPaginationState, pageSize: initialPageSize } : initialPaginationState
|
|
60
|
-
}),
|
|
61
|
-
|
|
62
|
-
withComputed(({ pagination: { page, pageSize, totalCount } }) => ({
|
|
63
|
-
paginationComputed: computed(() => ({
|
|
64
|
-
hasNext: page() < Math.ceil(totalCount() / pageSize()),
|
|
65
|
-
hasPrevious: page() > 1,
|
|
66
|
-
totalPages: Math.ceil(totalCount() / pageSize())
|
|
67
|
-
}))
|
|
68
|
-
})),
|
|
69
|
-
withMethods((store) => ({
|
|
70
|
-
nextPage: () => {
|
|
71
|
-
if (store.pagination.page() < Math.ceil(store.pagination.totalCount() / store.pagination.pageSize())) {
|
|
72
|
-
patchState(store, (state) => ({ pagination: { ...state.pagination, page: store.pagination.page() + 1 } }));
|
|
73
|
-
}
|
|
74
|
-
},
|
|
75
|
-
previousPage: () => {
|
|
76
|
-
if (store.pagination.page() > 1) {
|
|
77
|
-
patchState(store, (state) => ({ pagination: { ...state.pagination, page: store.pagination.page() - 1 } }));
|
|
78
|
-
}
|
|
79
|
-
},
|
|
80
|
-
setPage: (page: number) => {
|
|
81
|
-
patchState(store, (state) => ({ pagination: { ...state.pagination, page } }));
|
|
82
|
-
},
|
|
83
|
-
setPageSize: (pageSize: number) =>
|
|
84
|
-
patchState(store, (state) => ({ pagination: { ...state.pagination, page: 1, pageSize } })), // Reset a pág 1 si cambia el tamaño
|
|
85
|
-
setTotalCount: (totalCount: number) =>
|
|
86
|
-
patchState(store, (state) => ({ pagination: { ...state.pagination, totalCount } }))
|
|
87
|
-
}))
|
|
88
|
-
);
|
|
89
|
-
}
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { computed, Signal } from '@angular/core';
|
|
2
|
-
import { EmptyFeatureResult, SignalStoreFeature, signalStoreFeature, withComputed, withState } from '@ngrx/signals';
|
|
3
|
-
|
|
4
|
-
export interface EntityStatus {
|
|
5
|
-
_removeLoading: boolean;
|
|
6
|
-
_updateLoading: boolean;
|
|
7
|
-
addError: Error | null;
|
|
8
|
-
addLoading: boolean;
|
|
9
|
-
error: Error | null;
|
|
10
|
-
idSelected: null | number | string;
|
|
11
|
-
idsRemoving: (number | string)[];
|
|
12
|
-
idsUpdating: (number | string)[];
|
|
13
|
-
loaded: boolean;
|
|
14
|
-
loading: boolean;
|
|
15
|
-
removeError: Error | null;
|
|
16
|
-
selectedError: Error | null;
|
|
17
|
-
selectedLoading: boolean;
|
|
18
|
-
updateError: Error | null;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
interface EntityStatusComputedProps {
|
|
22
|
-
anyError: Error | null;
|
|
23
|
-
isAnyActionLoading: boolean;
|
|
24
|
-
removeLoading: boolean;
|
|
25
|
-
updateLoading: boolean;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
type EntityStatusMethodProps = Record<string, (...args: unknown[]) => unknown>;
|
|
29
|
-
|
|
30
|
-
const initialState: EntityStatus = {
|
|
31
|
-
_removeLoading: false,
|
|
32
|
-
_updateLoading: false,
|
|
33
|
-
addError: null,
|
|
34
|
-
addLoading: false,
|
|
35
|
-
error: null,
|
|
36
|
-
idSelected: null,
|
|
37
|
-
idsRemoving: [],
|
|
38
|
-
idsUpdating: [],
|
|
39
|
-
loaded: false,
|
|
40
|
-
loading: false,
|
|
41
|
-
removeError: null,
|
|
42
|
-
selectedError: null,
|
|
43
|
-
selectedLoading: false,
|
|
44
|
-
updateError: null
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Resetea el estado de la entidad al estado inicial.
|
|
49
|
-
* @returns {EntityStatus} - El estado inicial de la entidad.
|
|
50
|
-
*/
|
|
51
|
-
export function resetEntityStatus(): EntityStatus {
|
|
52
|
-
return initialState;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Agrega funcionalidades comunes de estado y computados para manejar el estado de entidades.
|
|
57
|
-
* @returns {SignalStoreFeature} -Características de la tienda con estado y computados para el manejo de entidades.
|
|
58
|
-
*/
|
|
59
|
-
export function withEntityStatus(): SignalStoreFeature<
|
|
60
|
-
EmptyFeatureResult,
|
|
61
|
-
{
|
|
62
|
-
methods: EntityStatusMethodProps;
|
|
63
|
-
props: Record<'statusComputed', Signal<EntityStatusComputedProps>>;
|
|
64
|
-
state: Record<'status', EntityStatus>;
|
|
65
|
-
}
|
|
66
|
-
> {
|
|
67
|
-
return signalStoreFeature(
|
|
68
|
-
withState({ status: initialState }),
|
|
69
|
-
withComputed(
|
|
70
|
-
({
|
|
71
|
-
status: {
|
|
72
|
-
_removeLoading,
|
|
73
|
-
_updateLoading,
|
|
74
|
-
addError,
|
|
75
|
-
error,
|
|
76
|
-
idsRemoving,
|
|
77
|
-
idsUpdating,
|
|
78
|
-
removeError,
|
|
79
|
-
selectedError,
|
|
80
|
-
updateError
|
|
81
|
-
}
|
|
82
|
-
}) => ({
|
|
83
|
-
statusComputed: computed(() => ({
|
|
84
|
-
anyError: error() || addError() || removeError() || updateError() || selectedError(),
|
|
85
|
-
isAnyActionLoading: idsUpdating().length > 0 || idsRemoving().length > 0,
|
|
86
|
-
removeLoading: _removeLoading() || idsRemoving().length > 0,
|
|
87
|
-
updateLoading: _updateLoading() || idsUpdating().length > 0
|
|
88
|
-
}))
|
|
89
|
-
})
|
|
90
|
-
)
|
|
91
|
-
);
|
|
92
|
-
}
|