unictive-angular 1.1.4 → 1.1.6
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/bin/utils/auth.js +50 -21
- package/bin/utils/createProject.js +18 -1
- package/bin/utils/resource/src/app/app.config.ts +1 -18
- package/bin/utils/resource/src/app/shared/ui/button/button.component.ts +6 -9
- package/bin/utils/resource/src/app/shared/ui/input-text/input-text.component.ts +16 -9
- package/bin/utils/updatePackageJson.js +122 -124
- package/index.js +2 -2
- package/package.json +1 -1
package/bin/utils/auth.js
CHANGED
|
@@ -8,31 +8,60 @@ const CACHE_FILE = path.join(os.homedir(), ".my-cli-auth");
|
|
|
8
8
|
// Fungsi untuk minta password (input tersembunyi)
|
|
9
9
|
function askPassword(promptText) {
|
|
10
10
|
return new Promise((resolve) => {
|
|
11
|
-
const
|
|
12
|
-
input: process.stdin,
|
|
13
|
-
output: process.stdout
|
|
14
|
-
});
|
|
11
|
+
const stdin = process.stdin;
|
|
15
12
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
13
|
+
// non-tty (piped input): baca satu baris tanpa masking
|
|
14
|
+
if (!stdin.isTTY) {
|
|
15
|
+
const rl = readline.createInterface({ input: stdin, output: process.stdout });
|
|
16
|
+
rl.question(promptText, (password) => {
|
|
17
|
+
rl.close();
|
|
18
|
+
resolve(password);
|
|
19
|
+
});
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let password = "";
|
|
24
|
+
process.stdout.write(promptText);
|
|
25
|
+
|
|
26
|
+
const cleanup = () => {
|
|
27
|
+
stdin.removeListener("data", onData);
|
|
28
|
+
stdin.setRawMode(false);
|
|
29
|
+
stdin.pause();
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const onData = (chunk) => {
|
|
33
|
+
// abaikan tombol panah / escape sequence
|
|
34
|
+
if (chunk.startsWith("\u001b")) return;
|
|
35
|
+
|
|
36
|
+
for (const ch of chunk) {
|
|
37
|
+
if (ch === "\r" || ch === "\n" || ch === "\u0004") {
|
|
38
|
+
cleanup();
|
|
39
|
+
process.stdout.write("\n");
|
|
40
|
+
resolve(password);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (ch === "\u0003") {
|
|
44
|
+
cleanup();
|
|
22
45
|
process.stdout.write("\n");
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
46
|
+
process.exit(130);
|
|
47
|
+
}
|
|
48
|
+
if (ch === "\u0008" || ch === "\u007f") {
|
|
49
|
+
if (password.length) {
|
|
50
|
+
password = password.slice(0, -1);
|
|
51
|
+
process.stdout.write("\b \b");
|
|
52
|
+
}
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (ch < " ") continue;
|
|
56
|
+
password += ch;
|
|
57
|
+
process.stdout.write("*");
|
|
29
58
|
}
|
|
30
|
-
}
|
|
59
|
+
};
|
|
31
60
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
61
|
+
stdin.setEncoding("utf8");
|
|
62
|
+
stdin.setRawMode(true);
|
|
63
|
+
stdin.resume();
|
|
64
|
+
stdin.on("data", onData);
|
|
36
65
|
});
|
|
37
66
|
}
|
|
38
67
|
|
|
@@ -107,7 +107,24 @@ async function create_project() {
|
|
|
107
107
|
// let cmd = `ng new ${projectName} ${zoneless ? "--zoneless" : ""} --ssr=false --skip-git --style=css`;
|
|
108
108
|
let cmd = `ng new ${projectName} --zoneless --ssr=false --skip-git --style=css`;
|
|
109
109
|
// let cmd = `ng new ${projectName} --ssr=false --skip-git --style=css`;
|
|
110
|
-
|
|
110
|
+
|
|
111
|
+
// di windows, handle stdin milik node masih "membaca" console walau sudah di-pause,
|
|
112
|
+
// sehingga ketikan tidak sampai ke prompt angular. tutup handle-nya (fd 0 tetap diwarisi child)
|
|
113
|
+
// dan beri event loop satu tick agar pembatalan read selesai.
|
|
114
|
+
if (process.stdin.isTTY) process.stdin.setRawMode(false);
|
|
115
|
+
process.stdin.pause();
|
|
116
|
+
process.stdin.destroy();
|
|
117
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
118
|
+
|
|
119
|
+
const code = await new Promise((resolve) => {
|
|
120
|
+
const child = spawn(cmd.trim(), { stdio: "inherit", shell: true });
|
|
121
|
+
child.on("error", () => resolve(1));
|
|
122
|
+
child.on("close", resolve);
|
|
123
|
+
});
|
|
124
|
+
if (code !== 0 || !fs.existsSync(projectName)) {
|
|
125
|
+
show_status("Gagal membuat project Angular!", "error");
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
111
128
|
process.chdir(projectName);
|
|
112
129
|
show_status("Project berhasil dibuat!", "success");
|
|
113
130
|
return projectName;
|
|
@@ -14,8 +14,7 @@ import { errorInterceptor } from '@core/interceptors/error.interceptor';
|
|
|
14
14
|
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
|
|
15
15
|
|
|
16
16
|
import { AuthService } from '@api/auth/auth.service';
|
|
17
|
-
|
|
18
|
-
import Aura from '@primeuix/themes/aura';
|
|
17
|
+
|
|
19
18
|
|
|
20
19
|
export function appInitFactoryFromApi(auth: AuthService) {
|
|
21
20
|
return auth.initFromApi();
|
|
@@ -30,21 +29,5 @@ export const appConfig: ApplicationConfig = {
|
|
|
30
29
|
provideHttpClient(withInterceptors([jwtInterceptor, errorInterceptor])),
|
|
31
30
|
provideAppInitializer(() => appInitFactoryFromApi(inject(AuthService))),
|
|
32
31
|
|
|
33
|
-
providePrimeNG({
|
|
34
|
-
theme: {
|
|
35
|
-
preset: Aura,
|
|
36
|
-
options: {
|
|
37
|
-
darkModeSelector: '[data-theme="dark"]',
|
|
38
|
-
lightModeSelector: '[data-theme="light"]',
|
|
39
|
-
},
|
|
40
|
-
},
|
|
41
|
-
|
|
42
|
-
zIndex: {
|
|
43
|
-
modal: 1100, // dialog, sidebar
|
|
44
|
-
overlay: 1000, // dropdown, overlaypanel
|
|
45
|
-
menu: 1000, // overlay menus
|
|
46
|
-
tooltip: 1100 // tooltip
|
|
47
|
-
}
|
|
48
|
-
}),
|
|
49
32
|
],
|
|
50
33
|
};
|
|
@@ -1,31 +1,28 @@
|
|
|
1
1
|
import { NgClass } from '@angular/common';
|
|
2
2
|
import { Component, computed, EventEmitter, Input, input, OnInit, Output, signal } from '@angular/core';
|
|
3
|
-
import { ButtonModule } from 'primeng/button';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
// import { ButtonModule } from 'primeng/button';
|
|
7
3
|
|
|
8
4
|
@Component({
|
|
9
5
|
selector: 'app-button',
|
|
10
6
|
template: `
|
|
11
7
|
<button
|
|
12
|
-
pButton
|
|
13
8
|
[type]="type"
|
|
14
9
|
[disabled]="isDisabled()"
|
|
15
10
|
[ngClass]="[class, variantClass]"
|
|
16
|
-
|
|
17
|
-
class="rounded-xl! flex items-center text-sm!"
|
|
11
|
+
class="inline-flex items-center justify-center gap-2 px-4 py-2 border rounded-xl text-sm font-medium cursor-pointer transition-colors disabled:opacity-60 disabled:cursor-not-allowed"
|
|
18
12
|
(click)="handleClick()"
|
|
19
13
|
>
|
|
20
14
|
@if (loadings() && loading) {
|
|
21
|
-
<
|
|
15
|
+
<svg class="size-4 animate-spin" viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
|
16
|
+
<circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" class="opacity-25" />
|
|
17
|
+
<path d="M22 12a10 10 0 0 0-10-10" stroke="currentColor" stroke-width="4" stroke-linecap="round" />
|
|
18
|
+
</svg>
|
|
22
19
|
}
|
|
23
20
|
<ng-content>
|
|
24
21
|
Label
|
|
25
22
|
</ng-content>
|
|
26
23
|
</button>
|
|
27
24
|
`,
|
|
28
|
-
imports: [
|
|
25
|
+
imports: [NgClass],
|
|
29
26
|
})
|
|
30
27
|
export class ButtonComponent implements OnInit {
|
|
31
28
|
|
|
@@ -2,7 +2,6 @@ import { CommonModule } from '@angular/common';
|
|
|
2
2
|
import { Component, forwardRef, input, Input, OnInit } from '@angular/core';
|
|
3
3
|
import { ControlValueAccessor, FormControl, FormsModule, NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms';
|
|
4
4
|
import { AlertErrorInputComponent } from '@shared/widgets/alert-error-input/alert-error-input.component';
|
|
5
|
-
import { FloatLabelModule } from "primeng/floatlabel";
|
|
6
5
|
|
|
7
6
|
@Component({
|
|
8
7
|
selector: 'input-text',
|
|
@@ -11,7 +10,6 @@ import { FloatLabelModule } from "primeng/floatlabel";
|
|
|
11
10
|
ReactiveFormsModule,
|
|
12
11
|
FormsModule,
|
|
13
12
|
AlertErrorInputComponent,
|
|
14
|
-
FloatLabelModule,
|
|
15
13
|
CommonModule
|
|
16
14
|
],
|
|
17
15
|
providers: [
|
|
@@ -28,13 +26,22 @@ import { FloatLabelModule } from "primeng/floatlabel";
|
|
|
28
26
|
@if(this.type == 'password'){
|
|
29
27
|
<div class="relative">
|
|
30
28
|
<input [autocomplete]="false" (ngModelChange)="onValueChange($event)" [(ngModel)]="value" [type]="showPassword ? 'text' : type"
|
|
31
|
-
class="w-full p-0! border-none! rounded-lg focus:outline-none! focus:ring-0"
|
|
32
|
-
[placeholder]="placeholder()" />
|
|
33
|
-
<
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
29
|
+
class="w-full p-0! pr-6! border-none! rounded-lg focus:outline-none! focus:ring-0"
|
|
30
|
+
[placeholder]="placeholder()" />
|
|
31
|
+
<button
|
|
32
|
+
type="button"
|
|
33
|
+
class="absolute right-0 top-1/2 -translate-y-1/2 cursor-pointer text-gray-500 hover:text-gray-700"
|
|
34
|
+
[attr.aria-label]="showPassword ? 'Sembunyikan password' : 'Tampilkan password'"
|
|
35
|
+
(click)="togglePassword()"
|
|
36
|
+
>
|
|
37
|
+
<svg class="size-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
38
|
+
<path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7S2 12 2 12z" />
|
|
39
|
+
<circle cx="12" cy="12" r="3" />
|
|
40
|
+
@if (!showPassword) {
|
|
41
|
+
<line x1="3" y1="3" x2="21" y2="21" />
|
|
42
|
+
}
|
|
43
|
+
</svg>
|
|
44
|
+
</button>
|
|
38
45
|
</div>
|
|
39
46
|
}
|
|
40
47
|
@else {
|
|
@@ -1,124 +1,122 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const { show_status } = require('./showStatus');
|
|
3
|
-
const { execSync} = require("child_process");
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const listPackagesToInstall = [
|
|
7
|
-
"npm i tailwindcss @tailwindcss/postcss postcss --force",
|
|
8
|
-
"npm i @ngx-pwa/local-storage ",
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
pkg.scripts =
|
|
29
|
-
pkg.scripts["start:
|
|
30
|
-
|
|
31
|
-
pkg.scripts["
|
|
32
|
-
|
|
33
|
-
pkg.scripts["build:
|
|
34
|
-
pkg.scripts["
|
|
35
|
-
|
|
36
|
-
pkg.scripts["
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
show_status(`
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
-
//
|
|
73
|
-
|
|
74
|
-
//
|
|
75
|
-
|
|
76
|
-
//
|
|
77
|
-
|
|
78
|
-
// const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
//
|
|
82
|
-
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
|
|
86
|
-
// }
|
|
87
|
-
|
|
88
|
-
//
|
|
89
|
-
|
|
90
|
-
//
|
|
91
|
-
//
|
|
92
|
-
//
|
|
93
|
-
//
|
|
94
|
-
//
|
|
95
|
-
//
|
|
96
|
-
//
|
|
97
|
-
|
|
98
|
-
//
|
|
99
|
-
|
|
100
|
-
//
|
|
101
|
-
//
|
|
102
|
-
//
|
|
103
|
-
//
|
|
104
|
-
//
|
|
105
|
-
//
|
|
106
|
-
|
|
107
|
-
//
|
|
108
|
-
|
|
109
|
-
//
|
|
110
|
-
//
|
|
111
|
-
//
|
|
112
|
-
//
|
|
113
|
-
//
|
|
114
|
-
//
|
|
115
|
-
|
|
116
|
-
//
|
|
117
|
-
|
|
118
|
-
//
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
module.exports = {update_package_json };
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const { show_status } = require('./showStatus');
|
|
3
|
+
const { execSync} = require("child_process");
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
const listPackagesToInstall = [
|
|
7
|
+
"npm i tailwindcss @tailwindcss/postcss postcss --force",
|
|
8
|
+
"npm i @ngx-pwa/local-storage ",
|
|
9
|
+
"npm i sweetalert2 ",
|
|
10
|
+
"npm i @angular/animations ",
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
// ===================== Update package.json =====================
|
|
15
|
+
async function update_package_json() {
|
|
16
|
+
show_status("Memperbarui package.json...", "info");
|
|
17
|
+
|
|
18
|
+
const pkgPath = "package.json";
|
|
19
|
+
const angularJsonPath = "angular.json";
|
|
20
|
+
|
|
21
|
+
// ------------------- Backup -------------------
|
|
22
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
23
|
+
fs.copyFileSync(pkgPath, "package.json.backup");
|
|
24
|
+
|
|
25
|
+
// ------------------- Scripts -------------------
|
|
26
|
+
pkg.scripts = pkg.scripts || {};
|
|
27
|
+
pkg.scripts["start:dev"] = "ng serve --configuration=dev --port 4200 --open";
|
|
28
|
+
pkg.scripts["start:staging"] = "ng serve --configuration=staging --port 4200 --open";
|
|
29
|
+
pkg.scripts["start:prod"] = "ng serve --configuration=production --port 4200 --open";
|
|
30
|
+
|
|
31
|
+
pkg.scripts["build:dev"] = "ng build --configuration=dev";
|
|
32
|
+
pkg.scripts["build:staging"] = "ng build --configuration=staging";
|
|
33
|
+
pkg.scripts["build:prod"] = "ng build --configuration=production";
|
|
34
|
+
pkg.scripts["staging"] = "git pull && npm run build:staging";
|
|
35
|
+
|
|
36
|
+
pkg.scripts["lint"] = "ng lint";
|
|
37
|
+
pkg.scripts["test"] = "ng test --watch=false";
|
|
38
|
+
|
|
39
|
+
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
|
|
40
|
+
show_status("package.json berhasil diperbarui dengan script build multi-env!", "success");
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
// ------------------- Bin -------------------
|
|
45
|
+
pkg.bin = pkg.bin || {};
|
|
46
|
+
pkg.bin["dx"] = "./tools/dx.js";
|
|
47
|
+
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
|
|
48
|
+
show_status('Menambahkan field "bin" ke package.json!', "success");
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
listPackagesToInstall.forEach(command => {
|
|
52
|
+
console.log(`Menjalankan: ${command}`);
|
|
53
|
+
try {
|
|
54
|
+
execSync(command, { stdio: 'inherit' });
|
|
55
|
+
show_status(`Berhasil menjalankan: ${command}`, "success");
|
|
56
|
+
} catch (error) {
|
|
57
|
+
show_status(`Gagal menjalankan: ${command}`, "error");
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
// ------------------- Angular file replacements -------------------
|
|
67
|
+
// if (!fs.existsSync(angularJsonPath)) {
|
|
68
|
+
// show_status("⚠ angular.json tidak ditemukan! Lewati file replacement.", "warning");
|
|
69
|
+
// return;
|
|
70
|
+
// }
|
|
71
|
+
|
|
72
|
+
// const angularJson = JSON.parse(fs.readFileSync(angularJsonPath, "utf8"));
|
|
73
|
+
|
|
74
|
+
// // Pilih project
|
|
75
|
+
// const projectNames = Object.keys(angularJson.projects);
|
|
76
|
+
// const projectName = angularJson.defaultProject || projectNames[0];
|
|
77
|
+
|
|
78
|
+
// const project = angularJson.projects[projectName];
|
|
79
|
+
// const buildTarget = project.architect?.build || project.targets?.build;
|
|
80
|
+
|
|
81
|
+
// if (!buildTarget) {
|
|
82
|
+
// show_status("⚠ Build target tidak ditemukan di angular.json!", "error");
|
|
83
|
+
// return;
|
|
84
|
+
// }
|
|
85
|
+
|
|
86
|
+
// const buildConfig = buildTarget.configurations || {};
|
|
87
|
+
|
|
88
|
+
// // ------------------- Tambahkan environment config -------------------
|
|
89
|
+
// buildConfig["dev"] = {
|
|
90
|
+
// fileReplacements: [
|
|
91
|
+
// {
|
|
92
|
+
// replace: "src/environments/environment.ts",
|
|
93
|
+
// with: "src/environments/environment.dev.ts"
|
|
94
|
+
// }
|
|
95
|
+
// ]
|
|
96
|
+
// };
|
|
97
|
+
|
|
98
|
+
// buildConfig["staging"] = {
|
|
99
|
+
// fileReplacements: [
|
|
100
|
+
// {
|
|
101
|
+
// replace: "src/environments/environment.ts",
|
|
102
|
+
// with: "src/environments/environment.staging.ts"
|
|
103
|
+
// }
|
|
104
|
+
// ]
|
|
105
|
+
// };
|
|
106
|
+
|
|
107
|
+
// buildConfig["production"] = {
|
|
108
|
+
// fileReplacements: [
|
|
109
|
+
// {
|
|
110
|
+
// replace: "src/environments/environment.ts",
|
|
111
|
+
// with: "src/environments/environment.prod.ts"
|
|
112
|
+
// }
|
|
113
|
+
// ]
|
|
114
|
+
// };
|
|
115
|
+
|
|
116
|
+
// buildTarget.configurations = buildConfig;
|
|
117
|
+
|
|
118
|
+
// fs.writeFileSync(angularJsonPath, JSON.stringify(angularJson, null, 2));
|
|
119
|
+
// show_status("angular.json berhasil diperbarui dengan file replacement multi-env!", "success");
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
module.exports = {update_package_json };
|
package/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Script installer Angular Project dengan struktur kustom
|
|
@@ -136,7 +136,7 @@ async function check_dependencies() {
|
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
const ngVersion = execSync("ng version").toString().split("\n").find((l) => l.includes("Angular CLI"));
|
|
139
|
-
await run_with_spinner("ng version", "Memeriksa Angular CLI...", `Angular CLI: ${ngVersion?.split("
|
|
139
|
+
await run_with_spinner("ng version", "Memeriksa Angular CLI...", `Angular CLI: ${ngVersion?.split(":")[1]?.trim() || "Unknown"}`, "Angular CLI terinstall, tapi tidak bisa baca versi");
|
|
140
140
|
console.log("");
|
|
141
141
|
}
|
|
142
142
|
|
package/package.json
CHANGED