@postgres.ai/shared 4.0.2 → 4.0.4
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/helpers/getEntropy.d.ts +8 -0
- package/helpers/getEntropy.js +39 -0
- package/icons/PostgresSQL/index.js +1 -39
- package/package.json +1 -1
- package/pages/CreateClone/index.js +50 -24
- package/pages/CreateClone/stores/Main.d.ts +1 -1
- package/pages/CreateClone/stores/Main.js +2 -1
- package/pages/CreateClone/styles.module.scss +14 -0
- package/pages/CreateClone/useForm.d.ts +1 -0
- package/pages/CreateClone/useForm.js +1 -0
- package/pages/CreateClone/utils/index.d.ts +1 -1
- package/pages/CreateClone/utils/index.js +18 -7
- package/pages/Instance/Configuration/index.js +3 -1
- package/pages/Instance/Snapshots/components/SnapshotsList/index.js +1 -1
package/helpers/getEntropy.d.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
1
|
export declare const MIN_ENTROPY = 60;
|
|
2
2
|
export declare function getEntropy(password: string): number;
|
|
3
|
+
/**
|
|
4
|
+
* generates a cryptographically secure random password with guaranteed character diversity
|
|
5
|
+
*
|
|
6
|
+
* @param length - desired password length, constrained to 4-128 characters (default: 16)
|
|
7
|
+
* @returns a random password containing at least one character from each category:
|
|
8
|
+
* lowercase letters, uppercase letters, digits, and special characters (!@$&*_-.)
|
|
9
|
+
*/
|
|
10
|
+
export declare function generatePassword(length?: number): string;
|
|
3
11
|
export declare function validatePassword(password: string, minEntropy: number): string;
|
package/helpers/getEntropy.js
CHANGED
|
@@ -158,6 +158,45 @@ function logPow(expBase, pow, logBase) {
|
|
|
158
158
|
}
|
|
159
159
|
return total;
|
|
160
160
|
}
|
|
161
|
+
function getSecureRandomInt(max) {
|
|
162
|
+
const array = new Uint32Array(1);
|
|
163
|
+
crypto.getRandomValues(array);
|
|
164
|
+
return array[0] % max;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* generates a cryptographically secure random password with guaranteed character diversity
|
|
168
|
+
*
|
|
169
|
+
* @param length - desired password length, constrained to 4-128 characters (default: 16)
|
|
170
|
+
* @returns a random password containing at least one character from each category:
|
|
171
|
+
* lowercase letters, uppercase letters, digits, and special characters (!@$&*_-.)
|
|
172
|
+
*/
|
|
173
|
+
export function generatePassword(length = 16) {
|
|
174
|
+
const minLength = 4;
|
|
175
|
+
const maxLength = 128;
|
|
176
|
+
const actualLength = Math.max(Math.min(length, maxLength), minLength);
|
|
177
|
+
const lowercase = 'abcdefghijklmnopqrstuvwxyz';
|
|
178
|
+
const uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
179
|
+
const digits = '0123456789';
|
|
180
|
+
const special = '!@$&*_-.';
|
|
181
|
+
const allChars = lowercase + uppercase + digits + special;
|
|
182
|
+
let password = '';
|
|
183
|
+
// ensure at least one character from each category
|
|
184
|
+
password += lowercase[getSecureRandomInt(lowercase.length)];
|
|
185
|
+
password += uppercase[getSecureRandomInt(uppercase.length)];
|
|
186
|
+
password += digits[getSecureRandomInt(digits.length)];
|
|
187
|
+
password += special[getSecureRandomInt(special.length)];
|
|
188
|
+
// fill the rest with random characters
|
|
189
|
+
for (let i = password.length; i < actualLength; i++) {
|
|
190
|
+
password += allChars[getSecureRandomInt(allChars.length)];
|
|
191
|
+
}
|
|
192
|
+
// shuffle the password to randomize positions (Fisher-Yates)
|
|
193
|
+
const shuffled = password.split('');
|
|
194
|
+
for (let i = shuffled.length - 1; i > 0; i--) {
|
|
195
|
+
const j = getSecureRandomInt(i + 1);
|
|
196
|
+
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
|
|
197
|
+
}
|
|
198
|
+
return shuffled.join('');
|
|
199
|
+
}
|
|
161
200
|
export function validatePassword(password, minEntropy) {
|
|
162
201
|
const entropy = getEntropy(password);
|
|
163
202
|
if (entropy >= minEntropy) {
|
|
@@ -1,40 +1,2 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
export const PostgresSQLIcon = () => (_jsxs("svg", { className: "postgres-logo",
|
|
3
|
-
fillRule: 'nonzero',
|
|
4
|
-
clipRule: 'nonzero',
|
|
5
|
-
stroke: '#000000',
|
|
6
|
-
strokeMiterlimit: 4,
|
|
7
|
-
} }), _jsxs("g", { id: "Layer_x0020_3", style: {
|
|
8
|
-
fillRule: 'nonzero',
|
|
9
|
-
clipRule: 'nonzero',
|
|
10
|
-
stroke: '#FFFFFF',
|
|
11
|
-
strokeWidth: 12.4651,
|
|
12
|
-
strokeLinecap: 'round',
|
|
13
|
-
strokeLinejoin: 'round',
|
|
14
|
-
strokeMiterlimit: 4,
|
|
15
|
-
}, children: [_jsx("path", { style: {
|
|
16
|
-
fill: '#000000',
|
|
17
|
-
stroke: '#000000',
|
|
18
|
-
strokeWidth: 37.3953,
|
|
19
|
-
strokeLinecap: 'butt',
|
|
20
|
-
strokeLinejoin: 'miter',
|
|
21
|
-
strokeMiterlimit: 4,
|
|
22
|
-
}, d: "M323.205,324.227c2.833-23.601,1.984-27.062,19.563-23.239l4.463,0.392c13.517,0.615,31.199-2.174,41.587-7c22.362-10.376,35.622-27.7,13.572-23.148c-50.297,10.376-53.755-6.655-53.755-6.655c53.111-78.803,75.313-178.836,56.149-203.322 C352.514-5.534,262.036,26.049,260.522,26.869l-0.482,0.089c-9.938-2.062-21.06-3.294-33.554-3.496c-22.761-0.374-40.032,5.967-53.133,15.904c0,0-161.408-66.498-153.899,83.628c1.597,31.936,45.777,241.655,98.47,178.31 c19.259-23.163,37.871-42.748,37.871-42.748c9.242,6.14,20.307,9.272,31.912,8.147l0.897-0.765c-0.281,2.876-0.157,5.689,0.359,9.019c-13.572,15.167-9.584,17.83-36.723,23.416c-27.457,5.659-11.326,15.734-0.797,18.367c12.768,3.193,42.305,7.716,62.268-20.224 l-0.795,3.188c5.325,4.26,4.965,30.619,5.72,49.452c0.756,18.834,2.017,36.409,5.856,46.771c3.839,10.36,8.369,37.05,44.036,29.406c29.809-6.388,52.6-15.582,54.677-101.107" }), _jsx("path", { style: {
|
|
23
|
-
fill: '#336791',
|
|
24
|
-
stroke: 'none',
|
|
25
|
-
}, d: "M402.395,271.23c-50.302,10.376-53.76-6.655-53.76-6.655c53.111-78.808,75.313-178.843,56.153-203.326c-52.27-66.785-142.752-35.2-144.262-34.38l-0.486,0.087c-9.938-2.063-21.06-3.292-33.56-3.496c-22.761-0.373-40.026,5.967-53.127,15.902 c0,0-161.411-66.495-153.904,83.63c1.597,31.938,45.776,241.657,98.471,178.312c19.26-23.163,37.869-42.748,37.869-42.748c9.243,6.14,20.308,9.272,31.908,8.147l0.901-0.765c-0.28,2.876-0.152,5.689,0.361,9.019c-13.575,15.167-9.586,17.83-36.723,23.416 c-27.459,5.659-11.328,15.734-0.796,18.367c12.768,3.193,42.307,7.716,62.266-20.224l-0.796,3.188c5.319,4.26,9.054,27.711,8.428,48.969c-0.626,21.259-1.044,35.854,3.147,47.254c4.191,11.4,8.368,37.05,44.042,29.406c29.809-6.388,45.256-22.942,47.405-50.555 c1.525-19.631,4.976-16.729,5.194-34.28l2.768-8.309c3.192-26.611,0.507-35.196,18.872-31.203l4.463,0.392c13.517,0.615,31.208-2.174,41.591-7c22.358-10.376,35.618-27.7,13.573-23.148z" }), _jsx("path", { d: "M215.866,286.484c-1.385,49.516,0.348,99.377,5.193,111.495c4.848,12.118,15.223,35.688,50.9,28.045c29.806-6.39,40.651-18.756,45.357-46.051c3.466-20.082,10.148-75.854,11.005-87.281" }), _jsx("path", { d: "M173.104,38.256c0,0-161.521-66.016-154.012,84.109c1.597,31.938,45.779,241.664,98.473,178.316c19.256-23.166,36.671-41.335,36.671-41.335" }), _jsx("path", { d: "M260.349,26.207c-5.591,1.753,89.848-34.889,144.087,34.417c19.159,24.484-3.043,124.519-56.153,203.329" }), _jsx("path", { style: {
|
|
26
|
-
strokeLinejoin: 'bevel',
|
|
27
|
-
}, d: "M348.282,263.953c0,0,3.461,17.036,53.764,6.653c22.04-4.552,8.776,12.774-13.577,23.155c-18.345,8.514-59.474,10.696-60.146-1.069c-1.729-30.355,21.647-21.133,19.96-28.739c-1.525-6.85-11.979-13.573-18.894-30.338 c-6.037-14.633-82.796-126.849,21.287-110.183c3.813-0.789-27.146-99.002-124.553-100.599c-97.385-1.597-94.19,119.762-94.19,119.762" }), _jsx("path", { d: "M188.604,274.334c-13.577,15.166-9.584,17.829-36.723,23.417c-27.459,5.66-11.326,15.733-0.797,18.365c12.768,3.195,42.307,7.718,62.266-20.229c6.078-8.509-0.036-22.086-8.385-25.547c-4.034-1.671-9.428-3.765-16.361,3.994z" }), _jsx("path", { d: "M187.715,274.069c-1.368-8.917,2.93-19.528,7.536-31.942c6.922-18.626,22.893-37.255,10.117-96.339c-9.523-44.029-73.396-9.163-73.436-3.193c-0.039,5.968,2.889,30.26-1.067,58.548c-5.162,36.913,23.488,68.132,56.479,64.938" }), _jsx("path", { style: {
|
|
28
|
-
fill: '#FFFFFF',
|
|
29
|
-
stroke: '#FFFFFF',
|
|
30
|
-
strokeWidth: 4.155,
|
|
31
|
-
strokeLinecap: 'butt',
|
|
32
|
-
strokeLinejoin: 'miter',
|
|
33
|
-
}, d: "M172.517,141.7c-0.288,2.039,3.733,7.48,8.976,8.207c5.234,0.73,9.714-3.522,9.998-5.559c0.284-2.039-3.732-4.285-8.977-5.015c-5.237-0.731-9.719,0.333-9.996,2.367z" }), _jsx("path", { style: {
|
|
34
|
-
fill: '#FFFFFF',
|
|
35
|
-
strokeWidth: 2.0775,
|
|
36
|
-
strokeLinecap: 'butt',
|
|
37
|
-
strokeLinejoin: 'miter',
|
|
38
|
-
}, d: "M331.941,137.543c0.284,2.039-3.732,7.48-8.976,8.207c-5.238,0.73-9.718-3.522-10.005-5.559c-0.277-2.039,3.74-4.285,8.979-5.015c5.239-0.73,9.718,0.333,10.002,2.368z" }), _jsx("path", { d: "M350.676,123.432c0.863,15.994-3.445,26.888-3.988,43.914c-0.804,24.748,11.799,53.074-7.191,81.435" }), _jsx("path", { style: {
|
|
39
|
-
strokeWidth: 3,
|
|
40
|
-
}, d: "M0,60.232" })] })] }));
|
|
2
|
+
export const PostgresSQLIcon = () => (_jsxs("svg", { className: "postgres-logo", viewBox: "0 0 128 128", xmlns: "http://www.w3.org/2000/svg", children: [_jsx("path", { d: "M93.809 92.112c.785-6.533.55-7.492 5.416-6.433l1.235.108c3.742.17 8.637-.602 11.513-1.938 6.191-2.873 9.861-7.668 3.758-6.409-13.924 2.873-14.881-1.842-14.881-1.842 14.703-21.815 20.849-49.508 15.543-56.287-14.47-18.489-39.517-9.746-39.936-9.52l-.134.025c-2.751-.571-5.83-.912-9.289-.968-6.301-.104-11.082 1.652-14.709 4.402 0 0-44.683-18.409-42.604 23.151.442 8.841 12.672 66.898 27.26 49.362 5.332-6.412 10.484-11.834 10.484-11.834 2.558 1.699 5.622 2.567 8.834 2.255l.249-.212c-.078.796-.044 1.575.099 2.497-3.757 4.199-2.653 4.936-10.166 6.482-7.602 1.566-3.136 4.355-.221 5.084 3.535.884 11.712 2.136 17.238-5.598l-.22.882c1.474 1.18 1.375 8.477 1.583 13.69.209 5.214.558 10.079 1.621 12.948 1.063 2.868 2.317 10.256 12.191 8.14 8.252-1.764 14.561-4.309 15.136-27.985" }), _jsx("path", { d: "M75.458 125.256c-4.367 0-7.211-1.689-8.938-3.32-2.607-2.46-3.641-5.629-4.259-7.522l-.267-.79c-1.244-3.358-1.666-8.193-1.916-14.419-.038-.935-.064-1.898-.093-2.919-.021-.747-.047-1.684-.085-2.664a18.8 18.8 0 01-4.962 1.568c-3.079.526-6.389.356-9.84-.507-2.435-.609-4.965-1.871-6.407-3.82-4.203 3.681-8.212 3.182-10.396 2.453-3.853-1.285-7.301-4.896-10.542-11.037-2.309-4.375-4.542-10.075-6.638-16.943-3.65-11.96-5.969-24.557-6.175-28.693C4.292 23.698 7.777 14.44 15.296 9.129 27.157.751 45.128 5.678 51.68 7.915c4.402-2.653 9.581-3.944 15.433-3.851 3.143.051 6.136.327 8.916.823 2.9-.912 8.628-2.221 15.185-2.139 12.081.144 22.092 4.852 28.949 13.615 4.894 6.252 2.474 19.381.597 26.651-2.642 10.226-7.271 21.102-12.957 30.57 1.544.011 3.781-.174 6.961-.831 6.274-1.295 8.109 2.069 8.607 3.575 1.995 6.042-6.677 10.608-9.382 11.864-3.466 1.609-9.117 2.589-13.745 2.377l-.202-.013-1.216-.107-.12 1.014-.116.991c-.311 11.999-2.025 19.598-5.552 24.619-3.697 5.264-8.835 6.739-13.361 7.709-1.544.33-2.947.474-4.219.474zm-9.19-43.671c2.819 2.256 3.066 6.501 3.287 14.434.028.99.054 1.927.089 2.802.106 2.65.355 8.855 1.327 11.477.137.371.26.747.39 1.146 1.083 3.316 1.626 4.979 6.309 3.978 3.931-.843 5.952-1.599 7.534-3.851 2.299-3.274 3.585-9.86 3.821-19.575l4.783.116-4.75-.57.14-1.186c.455-3.91.783-6.734 3.396-8.602 2.097-1.498 4.486-1.353 6.389-1.01-2.091-1.58-2.669-3.433-2.823-4.193l-.399-1.965 1.121-1.663c6.457-9.58 11.781-21.354 14.609-32.304 2.906-11.251 2.02-17.226 1.134-18.356-11.729-14.987-32.068-8.799-34.192-8.097l-.359.194-1.8.335-.922-.191c-2.542-.528-5.366-.82-8.393-.869-4.756-.08-8.593 1.044-11.739 3.431l-2.183 1.655-2.533-1.043c-5.412-2.213-21.308-6.662-29.696-.721-4.656 3.298-6.777 9.76-6.305 19.207.156 3.119 2.275 14.926 5.771 26.377 4.831 15.825 9.221 21.082 11.054 21.693.32.108 1.15-.537 1.976-1.529a270.708 270.708 0 0110.694-12.07l2.77-2.915 3.349 2.225c1.35.897 2.839 1.406 4.368 1.502l7.987-6.812-1.157 11.808c-.026.265-.039.626.065 1.296l.348 2.238-1.51 1.688-.174.196 4.388 2.025 1.836-2.301z" }), _jsx("path", { fill: "#336791", d: "M115.731 77.44c-13.925 2.873-14.882-1.842-14.882-1.842 14.703-21.816 20.849-49.51 15.545-56.287C101.924.823 76.875 9.566 76.457 9.793l-.135.024c-2.751-.571-5.83-.911-9.291-.967-6.301-.103-11.08 1.652-14.707 4.402 0 0-44.684-18.408-42.606 23.151.442 8.842 12.672 66.899 27.26 49.363 5.332-6.412 10.483-11.834 10.483-11.834 2.559 1.699 5.622 2.567 8.833 2.255l.25-.212c-.078.796-.042 1.575.1 2.497-3.758 4.199-2.654 4.936-10.167 6.482-7.602 1.566-3.136 4.355-.22 5.084 3.534.884 11.712 2.136 17.237-5.598l-.221.882c1.473 1.18 2.507 7.672 2.334 13.557-.174 5.885-.29 9.926.871 13.082 1.16 3.156 2.316 10.256 12.192 8.14 8.252-1.768 12.528-6.351 13.124-13.995.422-5.435 1.377-4.631 1.438-9.49l.767-2.3c.884-7.367.14-9.743 5.225-8.638l1.235.108c3.742.17 8.639-.602 11.514-1.938 6.19-2.871 9.861-7.667 3.758-6.408z" }), _jsx("path", { fill: "#fff", d: "M75.957 122.307c-8.232 0-10.84-6.519-11.907-9.185-1.562-3.907-1.899-19.069-1.551-31.503a1.59 1.59 0 011.64-1.55 1.594 1.594 0 011.55 1.639c-.401 14.341.168 27.337 1.324 30.229 1.804 4.509 4.54 8.453 12.275 6.796 7.343-1.575 10.093-4.359 11.318-11.46.94-5.449 2.799-20.951 3.028-24.01a1.593 1.593 0 011.71-1.472 1.597 1.597 0 011.472 1.71c-.239 3.185-2.089 18.657-3.065 24.315-1.446 8.387-5.185 12.191-13.794 14.037-1.463.313-2.792.453-4 .454zM31.321 90.466a6.71 6.71 0 01-2.116-.35c-5.347-1.784-10.44-10.492-15.138-25.885-3.576-11.717-5.842-23.947-6.041-27.922-.589-11.784 2.445-20.121 9.02-24.778 13.007-9.216 34.888-.44 35.813-.062a1.596 1.596 0 01-1.207 2.955c-.211-.086-21.193-8.492-32.768-.285-5.622 3.986-8.203 11.392-7.672 22.011.167 3.349 2.284 15.285 5.906 27.149 4.194 13.742 8.967 22.413 13.096 23.79.648.216 2.62.873 5.439-2.517A245.272 245.272 0 0145.88 73.046a1.596 1.596 0 012.304 2.208c-.048.05-4.847 5.067-10.077 11.359-2.477 2.979-4.851 3.853-6.786 3.853zm69.429-13.445a1.596 1.596 0 01-1.322-2.487c14.863-22.055 20.08-48.704 15.612-54.414-5.624-7.186-13.565-10.939-23.604-11.156-7.433-.16-13.341 1.738-14.307 2.069l-.243.099c-.971.305-1.716-.227-1.997-.849a1.6 1.6 0 01.631-2.025c.046-.027.192-.089.429-.176l-.021.006.021-.007c1.641-.601 7.639-2.4 15.068-2.315 11.108.118 20.284 4.401 26.534 12.388 2.957 3.779 2.964 12.485.019 23.887-3.002 11.625-8.651 24.118-15.497 34.277-.306.457-.81.703-1.323.703zm.76 10.21c-2.538 0-4.813-.358-6.175-1.174-1.4-.839-1.667-1.979-1.702-2.584-.382-6.71 3.32-7.878 5.208-8.411-.263-.398-.637-.866-1.024-1.349-1.101-1.376-2.609-3.26-3.771-6.078-.182-.44-.752-1.463-1.412-2.648-3.579-6.418-11.026-19.773-6.242-26.612 2.214-3.165 6.623-4.411 13.119-3.716C97.6 28.837 88.5 10.625 66.907 10.271c-6.494-.108-11.82 1.889-15.822 5.93-8.96 9.049-8.636 25.422-8.631 25.586a1.595 1.595 0 11-3.19.084c-.02-.727-.354-17.909 9.554-27.916C53.455 9.272 59.559 6.96 66.96 7.081c13.814.227 22.706 7.25 27.732 13.101 5.479 6.377 8.165 13.411 8.386 15.759.165 1.746-1.088 2.095-1.341 2.147l-.576.013c-6.375-1.021-10.465-.312-12.156 2.104-3.639 5.201 3.406 17.834 6.414 23.229.768 1.376 1.322 2.371 1.576 2.985.988 2.396 2.277 4.006 3.312 5.3.911 1.138 1.7 2.125 1.982 3.283.131.23 1.99 2.98 13.021.703 2.765-.57 4.423-.083 4.93 1.45.997 3.015-4.597 6.532-7.694 7.97-2.775 1.29-7.204 2.106-11.036 2.106zm-4.696-4.021c.35.353 2.101.962 5.727.806 3.224-.138 6.624-.839 8.664-1.786 2.609-1.212 4.351-2.567 5.253-3.492l-.5.092c-7.053 1.456-12.042 1.262-14.828-.577a6.162 6.162 0 01-.54-.401c-.302.119-.581.197-.78.253-1.58.443-3.214.902-2.996 5.105zm-45.562 8.915c-1.752 0-3.596-.239-5.479-.71-1.951-.488-5.24-1.957-5.19-4.37.057-2.707 3.994-3.519 5.476-3.824 5.354-1.103 5.703-1.545 7.376-3.67.488-.619 1.095-1.39 1.923-2.314 1.229-1.376 2.572-2.073 3.992-2.073.989 0 1.8.335 2.336.558 1.708.708 3.133 2.42 3.719 4.467.529 1.847.276 3.625-.71 5.006-3.237 4.533-7.886 6.93-13.443 6.93zm-7.222-4.943c.481.372 1.445.869 2.518 1.137 1.631.408 3.213.615 4.705.615 4.546 0 8.196-1.882 10.847-5.594.553-.774.387-1.757.239-2.274-.31-1.083-1.08-2.068-1.873-2.397-.43-.178-.787-.314-1.115-.314-.176 0-.712 0-1.614 1.009a41.146 41.146 0 00-1.794 2.162c-2.084 2.646-3.039 3.544-9.239 4.821-1.513.31-2.289.626-2.674.835zm12.269-7.36a1.596 1.596 0 01-1.575-1.354 8.218 8.218 0 01-.08-.799c-4.064-.076-7.985-1.82-10.962-4.926-3.764-3.927-5.477-9.368-4.699-14.927.845-6.037.529-11.366.359-14.229-.047-.796-.081-1.371-.079-1.769.003-.505.013-1.844 4.489-4.113 1.592-.807 4.784-2.215 8.271-2.576 5.777-.597 9.585 1.976 10.725 7.246 3.077 14.228.244 20.521-1.825 25.117-.385.856-.749 1.664-1.04 2.447l-.257.69c-1.093 2.931-2.038 5.463-1.748 7.354a1.595 1.595 0 01-1.335 1.819l-.244.02zM42.464 42.26l.062 1.139c.176 2.974.504 8.508-.384 14.86-.641 4.585.759 9.06 3.843 12.276 2.437 2.542 5.644 3.945 8.94 3.945h.068c.369-1.555.982-3.197 1.642-4.966l.255-.686c.329-.884.714-1.74 1.122-2.646 1.991-4.424 4.47-9.931 1.615-23.132-.565-2.615-1.936-4.128-4.189-4.627-4.628-1.022-11.525 2.459-12.974 3.837zm9.63-.677c-.08.564 1.033 2.07 2.485 2.271 1.449.203 2.689-.975 2.768-1.539.079-.564-1.033-1.186-2.485-1.388-1.451-.202-2.691.092-2.768.656zm2.818 2.826l-.407-.028c-.9-.125-1.81-.692-2.433-1.518-.219-.29-.576-.852-.505-1.354.101-.736.999-1.177 2.4-1.177.313 0 .639.023.967.069.766.106 1.477.327 2.002.62.91.508.977 1.075.936 1.368-.112.813-1.405 2.02-2.96 2.02zm-2.289-2.732c.045.348.907 1.496 2.029 1.651l.261.018c1.036 0 1.81-.815 1.901-1.082-.096-.182-.762-.634-2.025-.81a5.823 5.823 0 00-.821-.059c-.812 0-1.243.183-1.345.282zm43.605-1.245c.079.564-1.033 2.07-2.484 2.272-1.45.202-2.691-.975-2.771-1.539-.076-.564 1.036-1.187 2.486-1.388 1.45-.203 2.689.092 2.769.655zm-2.819 2.56c-1.396 0-2.601-1.086-2.7-1.791-.115-.846 1.278-1.489 2.712-1.688.316-.044.629-.066.93-.066 1.238 0 2.058.363 2.14.949.053.379-.238.964-.739 1.492-.331.347-1.026.948-1.973 1.079l-.37.025zm.943-3.013c-.276 0-.564.021-.856.061-1.441.201-2.301.779-2.259 1.089.048.341.968 1.332 2.173 1.332l.297-.021c.787-.109 1.378-.623 1.66-.919.443-.465.619-.903.598-1.052-.028-.198-.56-.49-1.613-.49zm3.965 32.843a1.594 1.594 0 01-1.324-2.483c3.398-5.075 2.776-10.25 2.175-15.255-.257-2.132-.521-4.337-.453-6.453.07-2.177.347-3.973.614-5.71.317-2.058.617-4.002.493-6.31a1.595 1.595 0 113.186-.172c.142 2.638-.197 4.838-.525 6.967-.253 1.643-.515 3.342-.578 5.327-.061 1.874.178 3.864.431 5.97.64 5.322 1.365 11.354-2.691 17.411a1.596 1.596 0 01-1.328.708z" })] }));
|
package/package.json
CHANGED
|
@@ -4,19 +4,21 @@ import { useEffect, useState } from 'react';
|
|
|
4
4
|
import { useHistory } from 'react-router-dom';
|
|
5
5
|
import { observer } from 'mobx-react-lite';
|
|
6
6
|
import { useTimer } from 'use-timer';
|
|
7
|
-
import { Paper, FormControlLabel, Checkbox } from '@material-ui/core';
|
|
8
|
-
import { Info as InfoIcon } from '@material-ui/icons';
|
|
7
|
+
import { Paper, FormControlLabel, Checkbox, IconButton, InputAdornment } from '@material-ui/core';
|
|
8
|
+
import { Info as InfoIcon, Visibility, VisibilityOff } from '@material-ui/icons';
|
|
9
|
+
import copy from 'copy-to-clipboard';
|
|
9
10
|
import { StubSpinner } from '@postgres.ai/shared/components/StubSpinnerFlex';
|
|
10
11
|
import { TextField } from '@postgres.ai/shared/components/TextField';
|
|
11
12
|
import { Select } from '@postgres.ai/shared/components/Select';
|
|
12
13
|
import { Button } from '@postgres.ai/shared/components/Button';
|
|
13
14
|
import { Spinner } from '@postgres.ai/shared/components/Spinner';
|
|
14
15
|
import { ErrorStub } from '@postgres.ai/shared/components/ErrorStub';
|
|
16
|
+
import { Tooltip } from '@postgres.ai/shared/components/Tooltip';
|
|
15
17
|
import { round } from '@postgres.ai/shared/utils/numbers';
|
|
16
18
|
import { formatBytesIEC } from '@postgres.ai/shared/utils/units';
|
|
17
19
|
import { SectionTitle } from '@postgres.ai/shared/components/SectionTitle';
|
|
18
20
|
import { SyntaxHighlight } from '@postgres.ai/shared/components/SyntaxHighlight';
|
|
19
|
-
import { MIN_ENTROPY, getEntropy, validatePassword, } from '@postgres.ai/shared/helpers/getEntropy';
|
|
21
|
+
import { MIN_ENTROPY, getEntropy, validatePassword, generatePassword, } from '@postgres.ai/shared/helpers/getEntropy';
|
|
20
22
|
import { useCreatedStores } from './useCreatedStores';
|
|
21
23
|
import { useForm } from './useForm';
|
|
22
24
|
import { getCliCloneStatus, getCliCreateCloneCommand } from './utils';
|
|
@@ -31,6 +33,9 @@ export const CreateClone = observer((props) => {
|
|
|
31
33
|
const [branchesList, setBranchesList] = useState([]);
|
|
32
34
|
const [snapshots, setSnapshots] = useState([]);
|
|
33
35
|
const [isLoadingSnapshots, setIsLoadingSnapshots] = useState(false);
|
|
36
|
+
const [selectedBranchKey, setSelectedBranchKey] = useState('');
|
|
37
|
+
const [showPassword, setShowPassword] = useState(false);
|
|
38
|
+
const [passwordGenerated, setPasswordGenerated] = useState(false);
|
|
34
39
|
// Form.
|
|
35
40
|
const onSubmit = async (values) => {
|
|
36
41
|
if (!values.dbPassword || getEntropy(values.dbPassword) < MIN_ENTROPY) {
|
|
@@ -45,38 +50,49 @@ export const CreateClone = observer((props) => {
|
|
|
45
50
|
timer.reset();
|
|
46
51
|
}
|
|
47
52
|
};
|
|
48
|
-
const fetchBranchSnapshotsData = async (branchName, initialSnapshotId) => {
|
|
53
|
+
const fetchBranchSnapshotsData = async (branchName, dataset, initialSnapshotId) => {
|
|
49
54
|
var _a;
|
|
50
|
-
const snapshotsRes = (_a = (await stores.main.getSnapshots(props.instanceId, branchName))) !== null && _a !== void 0 ? _a : [];
|
|
55
|
+
const snapshotsRes = (_a = (await stores.main.getSnapshots(props.instanceId, branchName, dataset))) !== null && _a !== void 0 ? _a : [];
|
|
51
56
|
setSnapshots(snapshotsRes);
|
|
52
57
|
const selectedSnapshot = snapshotsRes.find(s => s.id === initialSnapshotId) || snapshotsRes[0];
|
|
53
58
|
formik.setFieldValue('snapshotId', selectedSnapshot === null || selectedSnapshot === void 0 ? void 0 : selectedSnapshot.id);
|
|
54
59
|
};
|
|
55
60
|
const handleSelectBranch = async (e) => {
|
|
56
|
-
const
|
|
57
|
-
|
|
61
|
+
const compositeKey = e.target.value;
|
|
62
|
+
const [branchName, dataset] = compositeKey.split('|');
|
|
63
|
+
setSelectedBranchKey(compositeKey);
|
|
64
|
+
formik.setFieldValue('branch', branchName);
|
|
65
|
+
formik.setFieldValue('dataset', dataset);
|
|
58
66
|
if (props.api.getSnapshots) {
|
|
59
|
-
await fetchBranchSnapshotsData(
|
|
67
|
+
await fetchBranchSnapshotsData(branchName, dataset);
|
|
60
68
|
}
|
|
61
69
|
};
|
|
62
70
|
const formik = useForm(onSubmit);
|
|
63
71
|
const fetchData = async (initialBranch, initialSnapshotId) => {
|
|
64
|
-
var _a, _b, _c, _d, _e;
|
|
72
|
+
var _a, _b, _c, _d, _e, _f;
|
|
65
73
|
try {
|
|
66
74
|
setIsLoadingSnapshots(true);
|
|
67
75
|
await stores.main.load(props.instanceId);
|
|
68
76
|
const branches = (_a = (await stores.main.getBranches(props.instanceId))) !== null && _a !== void 0 ? _a : [];
|
|
69
|
-
let initiallySelectedBranch =
|
|
70
|
-
if (initialBranch
|
|
71
|
-
|
|
77
|
+
let initiallySelectedBranch = branches[0];
|
|
78
|
+
if (initialBranch) {
|
|
79
|
+
const foundBranch = branches.find((branch) => branch.name === initialBranch);
|
|
80
|
+
if (foundBranch) {
|
|
81
|
+
initiallySelectedBranch = foundBranch;
|
|
82
|
+
}
|
|
72
83
|
}
|
|
73
|
-
setBranchesList(branches
|
|
74
|
-
formik.setFieldValue('branch', initiallySelectedBranch);
|
|
75
|
-
|
|
76
|
-
|
|
84
|
+
setBranchesList(branches);
|
|
85
|
+
formik.setFieldValue('branch', (_b = initiallySelectedBranch === null || initiallySelectedBranch === void 0 ? void 0 : initiallySelectedBranch.name) !== null && _b !== void 0 ? _b : '');
|
|
86
|
+
formik.setFieldValue('dataset', (_c = initiallySelectedBranch === null || initiallySelectedBranch === void 0 ? void 0 : initiallySelectedBranch.dataset) !== null && _c !== void 0 ? _c : '');
|
|
87
|
+
if (initiallySelectedBranch) {
|
|
88
|
+
const compositeKey = `${initiallySelectedBranch.name}|${initiallySelectedBranch.dataset}`;
|
|
89
|
+
setSelectedBranchKey(compositeKey);
|
|
77
90
|
}
|
|
78
|
-
|
|
79
|
-
|
|
91
|
+
if (props.api.getSnapshots && initiallySelectedBranch) {
|
|
92
|
+
await fetchBranchSnapshotsData(initiallySelectedBranch.name, initiallySelectedBranch.dataset, initialSnapshotId);
|
|
93
|
+
}
|
|
94
|
+
else if (!props.api.getSnapshots) {
|
|
95
|
+
const allSnapshots = (_f = (_e = (_d = stores.main) === null || _d === void 0 ? void 0 : _d.snapshots) === null || _e === void 0 ? void 0 : _e.data) !== null && _f !== void 0 ? _f : [];
|
|
80
96
|
const sortedSnapshots = allSnapshots.slice().sort(compareSnapshotsDesc);
|
|
81
97
|
setSnapshots(sortedSnapshots);
|
|
82
98
|
let selectedSnapshot = allSnapshots.find(s => s.id === initialSnapshotId) || allSnapshots[0];
|
|
@@ -120,10 +136,10 @@ export const CreateClone = observer((props) => {
|
|
|
120
136
|
((_f = (_e = stores.main) === null || _e === void 0 ? void 0 : _e.snapshots) === null || _f === void 0 ? void 0 : _f.error) })] }));
|
|
121
137
|
const isCloneUnstable = Boolean(stores.main.clone && !stores.main.isCloneStable);
|
|
122
138
|
const isCreatingClone = (formik.isSubmitting || isCloneUnstable) && !stores.main.cloneError;
|
|
123
|
-
return (_jsxs(_Fragment, { children: [headRendered, _jsxs("div", { className: styles.container, children: [_jsxs("div", { className: styles.form, children: [_jsxs("div", { className: styles.section, children: [branchesList && branchesList.length > 0 && (_jsx(Select, { fullWidth: true, label: "Branch", value:
|
|
139
|
+
return (_jsxs(_Fragment, { children: [headRendered, _jsxs("div", { className: styles.container, children: [_jsxs("div", { className: styles.form, children: [_jsxs("div", { className: styles.section, children: [branchesList && branchesList.length > 0 && (_jsx(Select, { fullWidth: true, label: "Branch", value: selectedBranchKey, disabled: !branchesList || isCreatingClone, onChange: handleSelectBranch, error: Boolean(formik.errors.branch), items: (_g = branchesList === null || branchesList === void 0 ? void 0 : branchesList.map((branch) => {
|
|
124
140
|
return {
|
|
125
|
-
value:
|
|
126
|
-
children:
|
|
141
|
+
value: `${branch.name}|${branch.dataset}`,
|
|
142
|
+
children: `${branch.name} (${branch.dataset})`,
|
|
127
143
|
};
|
|
128
144
|
})) !== null && _g !== void 0 ? _g : [] })), _jsx(TextField, { fullWidth: true, label: "Clone ID", value: formik.values.cloneId, onChange: (e) => {
|
|
129
145
|
const sanitizedCloneIdValue = e.target.value.replace(/\s/g, '');
|
|
@@ -134,12 +150,22 @@ export const CreateClone = observer((props) => {
|
|
|
134
150
|
value: snapshot.id,
|
|
135
151
|
children: (_jsxs("div", { className: styles.snapshotItem, children: [_jsxs("strong", { className: styles.snapshotOverflow, children: [snapshot === null || snapshot === void 0 ? void 0 : snapshot.id, " ", isLatest && _jsx("span", { children: "Latest" })] }), (snapshot === null || snapshot === void 0 ? void 0 : snapshot.dataStateAt) && (_jsxs("p", { children: ["Data state at: ", snapshot === null || snapshot === void 0 ? void 0 : snapshot.dataStateAt] })), snapshot.message && (_jsxs("span", { children: ["Message: ", snapshot.message] }))] })),
|
|
136
152
|
};
|
|
137
|
-
})) !== null && _h !== void 0 ? _h : [] }), _jsx("p", { className: styles.remark, children: "By default latest snapshot of database is used. You can select\u00A0 different snapshots if earlier database state is needed." })] }), _jsxs("div", { className: styles.section, children: [_jsx("h2", { className: styles.title, children: "Database credentials *" }), _jsx("p", { className: styles.text, children: "Set custom credentials for the new clone. Save the password in reliable place, it can't be read later." }), _jsx(TextField, { fullWidth: true, label: "Database username *", value: formik.values.dbUser, onChange: (e) => formik.setFieldValue('dbUser', e.target.value), error: Boolean(formik.errors.dbUser), disabled: isCreatingClone }), _jsx(TextField, { fullWidth: true, label: "Database password *", type:
|
|
153
|
+
})) !== null && _h !== void 0 ? _h : [] }), _jsx("p", { className: styles.remark, children: "By default latest snapshot of database is used. You can select\u00A0 different snapshots if earlier database state is needed." })] }), _jsxs("div", { className: styles.section, children: [_jsx("h2", { className: styles.title, children: "Database credentials *" }), _jsx("p", { className: styles.text, children: "Set custom credentials for the new clone. Save the password in reliable place, it can't be read later." }), _jsx(TextField, { fullWidth: true, label: "Database username *", value: formik.values.dbUser, onChange: (e) => formik.setFieldValue('dbUser', e.target.value), error: Boolean(formik.errors.dbUser), disabled: isCreatingClone }), _jsx(TextField, { fullWidth: true, label: "Database password *", type: showPassword ? 'text' : 'password', value: formik.values.dbPassword, onChange: (e) => {
|
|
138
154
|
formik.setFieldValue('dbPassword', e.target.value);
|
|
155
|
+
setPasswordGenerated(false);
|
|
139
156
|
if (formik.errors.dbPassword) {
|
|
140
157
|
formik.setFieldError('dbPassword', '');
|
|
141
158
|
}
|
|
142
|
-
}, error: Boolean(formik.errors.dbPassword), disabled: isCreatingClone
|
|
159
|
+
}, error: Boolean(formik.errors.dbPassword), disabled: isCreatingClone, InputProps: {
|
|
160
|
+
endAdornment: (_jsx(InputAdornment, { position: "end", children: _jsx(Tooltip, { content: showPassword ? 'Hide password' : 'Show password', children: _jsx(IconButton, { size: "small", onClick: () => setShowPassword(!showPassword), disabled: isCreatingClone, style: { marginRight: 4 }, children: showPassword ? _jsx(Visibility, { fontSize: "small" }) : _jsx(VisibilityOff, { fontSize: "small" }) }) }) })),
|
|
161
|
+
} }), _jsxs("div", { className: styles.passwordActions, children: [_jsx(Button, { variant: "secondary", size: "small", onClick: () => copy(formik.values.dbPassword), isDisabled: isCreatingClone || !formik.values.dbPassword, children: "Copy" }), _jsx(Button, { variant: "secondary", size: "small", onClick: () => {
|
|
162
|
+
const newPassword = generatePassword(16);
|
|
163
|
+
formik.setFieldValue('dbPassword', newPassword);
|
|
164
|
+
setPasswordGenerated(true);
|
|
165
|
+
if (formik.errors.dbPassword) {
|
|
166
|
+
formik.setFieldError('dbPassword', '');
|
|
167
|
+
}
|
|
168
|
+
}, isDisabled: isCreatingClone, children: "Generate" }), passwordGenerated && (_jsx("span", { className: styles.passwordHint, children: "New password created. Copy and save it securely." }))] }), _jsx("p", { className: cn(formik.errors.dbPassword && styles.error, styles.remark), children: formik.errors.dbPassword })] }), _jsxs("div", { className: styles.section, children: [_jsx("h2", { className: styles.title, children: "Clone protection" }), _jsx(FormControlLabel, { label: "Enable deletion protection", control: _jsx(Checkbox, { checked: formik.values.isProtected, onChange: (e) => formik.setFieldValue('isProtected', e.target.checked), name: "protected", disabled: isCreatingClone }) }), _jsxs("p", { className: styles.remark, children: ["When enabled, no one can delete this clone and automated deletion is also disabled.", _jsx("br", {}), "Please be careful: abandoned clones with this checkbox enabled may cause out-of-disk-space events. Check disk space on a daily basis and delete this clone once the work is done."] })] }), _jsxs("div", { className: cn(styles.marginBottom, styles.section), children: [_jsxs(Paper, { className: styles.summary, children: [_jsx(InfoIcon, { className: styles.summaryIcon }), _jsxs("div", { className: styles.params, children: [_jsxs("p", { className: styles.param, children: [_jsx("span", { children: "Data size:" }), _jsx("strong", { children: ((_j = stores.main.instance.state) === null || _j === void 0 ? void 0 : _j.dataSize)
|
|
143
169
|
? formatBytesIEC(stores.main.instance.state.dataSize)
|
|
144
|
-
: '-' })] }), _jsxs("p", { className: styles.param, children: [_jsx("span", { children: "Expected cloning time:" }), _jsxs("strong", { children: [round((_k = stores.main.instance.state) === null || _k === void 0 ? void 0 : _k.cloning.expectedCloningTime, 2), ' ', "s"] })] })] })] }), stores.main.cloneError && (_jsx("div", { className: cn(styles.marginBottom, styles.section), children: _jsx(ErrorStub, { message: stores.main.cloneError }) })), _jsx("div", { className: styles.controls, children: _jsxs(Button, { onClick: formik.submitForm, variant: "primary", size: "medium", isDisabled: isCreatingClone, children: ["Create clone", isCreatingClone && (_jsx(Spinner, { size: "sm", className: styles.spinner }))] }) })] })] }), _jsx("div", { className: styles.form, children: _jsxs("div", { className: styles.snippetContainer, children: [_jsx(SectionTitle, { className: styles.title, tag: "h1", level: 1, text: "The same using CLI" }), _jsx("p", { className: styles.text, children: "Alternatively, you can create a new clone using CLI. Fill the form, copy the command below and paste it into your terminal." }), _jsx(SyntaxHighlight, { wrapLines: true, content: getCliCreateCloneCommand(formik.values) }), _jsx(SectionTitle, { className: styles.title, tag: "h2", level: 2, text: "Check clone status" }), _jsx("p", { className: styles.text, children: "To check the status of your newly created clone, use the command below." }), _jsx(SyntaxHighlight, { content: getCliCloneStatus(formik.values.cloneId) })] }) })] })] }));
|
|
170
|
+
: '-' })] }), _jsxs("p", { className: styles.param, children: [_jsx("span", { children: "Expected cloning time:" }), _jsxs("strong", { children: [round((_k = stores.main.instance.state) === null || _k === void 0 ? void 0 : _k.cloning.expectedCloningTime, 2), ' ', "s"] })] })] })] }), stores.main.cloneError && (_jsx("div", { className: cn(styles.marginBottom, styles.section), children: _jsx(ErrorStub, { message: stores.main.cloneError }) })), _jsx("div", { className: styles.controls, children: _jsxs(Button, { onClick: formik.submitForm, variant: "primary", size: "medium", isDisabled: isCreatingClone, children: ["Create clone", isCreatingClone && (_jsx(Spinner, { size: "sm", className: styles.spinner }))] }) })] })] }), _jsx("div", { className: styles.form, children: _jsxs("div", { className: styles.snippetContainer, children: [_jsx(SectionTitle, { className: styles.title, tag: "h1", level: 1, text: "The same using CLI" }), _jsx("p", { className: styles.text, children: "Alternatively, you can create a new clone using CLI. Fill the form, copy the command below and paste it into your terminal." }), _jsx(SyntaxHighlight, { wrapLines: true, content: getCliCreateCloneCommand(formik.values, showPassword) }), _jsx(SectionTitle, { className: styles.title, tag: "h2", level: 2, text: "Check clone status" }), _jsx("p", { className: styles.text, children: "To check the status of your newly created clone, use the command below." }), _jsx(SyntaxHighlight, { content: getCliCloneStatus(formik.values.cloneId) })] }) })] })] }));
|
|
145
171
|
});
|
|
@@ -31,7 +31,7 @@ export declare class MainStore {
|
|
|
31
31
|
load: (instanceId: string) => Promise<boolean | undefined>;
|
|
32
32
|
createClone: (data: FormValues) => Promise<boolean>;
|
|
33
33
|
getBranches: (instanceId: string) => Promise<import("@postgres.ai/shared/types/api/endpoints/getBranches").Branch[] | null | undefined>;
|
|
34
|
-
getSnapshots: (instanceId: string, branchName?: string) => Promise<{
|
|
34
|
+
getSnapshots: (instanceId: string, branchName?: string, dataset?: string) => Promise<{
|
|
35
35
|
createdAtDate: Date;
|
|
36
36
|
dataStateAtDate: Date;
|
|
37
37
|
numClones: string | number;
|
|
@@ -49,12 +49,13 @@ export class MainStore {
|
|
|
49
49
|
this.getBranchesError = await error.json().then((err) => err);
|
|
50
50
|
return response;
|
|
51
51
|
};
|
|
52
|
-
this.getSnapshots = async (instanceId, branchName) => {
|
|
52
|
+
this.getSnapshots = async (instanceId, branchName, dataset) => {
|
|
53
53
|
if (!this.api.getSnapshots)
|
|
54
54
|
return;
|
|
55
55
|
const { response, error } = await this.api.getSnapshots({
|
|
56
56
|
instanceId,
|
|
57
57
|
branchName,
|
|
58
|
+
dataset,
|
|
58
59
|
});
|
|
59
60
|
if (error)
|
|
60
61
|
this.getSnapshotsError = await error.json().then((err) => err);
|
|
@@ -111,4 +111,18 @@
|
|
|
111
111
|
.pageTitle {
|
|
112
112
|
margin-top: 8px;
|
|
113
113
|
line-height: 26px;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.passwordActions {
|
|
117
|
+
display: flex;
|
|
118
|
+
align-items: center;
|
|
119
|
+
gap: 8px;
|
|
120
|
+
margin-top: 8px;
|
|
121
|
+
margin-bottom: 16px;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.passwordHint {
|
|
125
|
+
font-size: 12px;
|
|
126
|
+
color: #f57c00;
|
|
127
|
+
font-weight: 500;
|
|
114
128
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { FormValues } from '@postgres.ai/shared/pages/CreateClone/useForm';
|
|
2
|
-
export declare const getCliCreateCloneCommand: (values: FormValues) => string;
|
|
2
|
+
export declare const getCliCreateCloneCommand: (values: FormValues, showPassword?: boolean) => string;
|
|
3
3
|
export declare const getCliCloneStatus: (cloneId: string) => string;
|
|
@@ -1,17 +1,28 @@
|
|
|
1
|
-
|
|
1
|
+
// escape string for use in single-quoted shell argument
|
|
2
|
+
const shellEscape = (str) => {
|
|
3
|
+
// replace single quotes with: end quote, escaped quote, start quote
|
|
4
|
+
return "'" + str.replace(/'/g, "'\\''") + "'";
|
|
5
|
+
};
|
|
6
|
+
export const getCliCreateCloneCommand = (values, showPassword) => {
|
|
2
7
|
const { dbUser, dbPassword, branch, isProtected, cloneId } = values;
|
|
8
|
+
const usernameDisplay = dbUser ? shellEscape(dbUser) : `<USERNAME>`;
|
|
9
|
+
const passwordDisplay = dbPassword
|
|
10
|
+
? (showPassword ? shellEscape(dbPassword) : dbPassword.replace(/./g, '*'))
|
|
11
|
+
: `<PASSWORD>`;
|
|
12
|
+
const cloneIdDisplay = cloneId ? shellEscape(cloneId) : `<CLONE_ID>`;
|
|
3
13
|
return `dblab clone create \
|
|
4
14
|
|
|
5
|
-
--username ${
|
|
15
|
+
--username ${usernameDisplay} \
|
|
6
16
|
|
|
7
|
-
--password ${
|
|
17
|
+
--password ${passwordDisplay} \
|
|
8
18
|
|
|
9
|
-
${branch ? `--branch ${branch}` : ``} \
|
|
19
|
+
${branch ? `--branch ${shellEscape(branch)}` : ``} \
|
|
10
20
|
|
|
11
|
-
${isProtected ? `--protected` : ''} \
|
|
21
|
+
${isProtected ? `--protected` : ''} \
|
|
12
22
|
|
|
13
|
-
--id ${
|
|
23
|
+
--id ${cloneIdDisplay} \ `;
|
|
14
24
|
};
|
|
15
25
|
export const getCliCloneStatus = (cloneId) => {
|
|
16
|
-
|
|
26
|
+
const cloneIdDisplay = cloneId ? shellEscape(cloneId) : `<CLONE_ID>`;
|
|
27
|
+
return `dblab clone status ${cloneIdDisplay}`;
|
|
17
28
|
};
|
|
@@ -316,7 +316,9 @@ export const Configuration = observer(({ instanceId, switchActiveTab, reload, is
|
|
|
316
316
|
dockerPath: initialRender
|
|
317
317
|
? formik.values.dockerPath
|
|
318
318
|
: data.map((image) => image.location)[0],
|
|
319
|
-
sharedPreloadLibraries:
|
|
319
|
+
sharedPreloadLibraries: initialRender
|
|
320
|
+
? formik.values.sharedPreloadLibraries
|
|
321
|
+
: currentPreloadLibraries || '',
|
|
320
322
|
});
|
|
321
323
|
}
|
|
322
324
|
else {
|
|
@@ -113,7 +113,7 @@ const SnapshotListItem = ({ snapshot, setSnapshotModal, openClonesModal, }) => {
|
|
|
113
113
|
const timeAgo = formatDistanceSafe(snapshot.createdAtDate);
|
|
114
114
|
const history = useHistory();
|
|
115
115
|
const host = useHost();
|
|
116
|
-
return (_jsx("div", { className: classes.commitItem, children: _jsxs("div", { className: classes.gridContainer, children: [_jsxs("div", { className: classes.infoBlock, children: [_jsx("div", { className: classes.header, children: snapshot.message || '-' }),
|
|
116
|
+
return (_jsx("div", { className: classes.commitItem, children: _jsxs("div", { className: classes.gridContainer, children: [_jsxs("div", { className: classes.infoBlock, children: [_jsx("div", { className: classes.header, children: snapshot.message || '-' }), _jsx("div", { className: classes.infoContent, title: snapshot.dataStateAt, children: timeAgo })] }), _jsxs("div", { className: classes.infoBlock, children: [_jsx("div", { className: classes.header, children: "Pool" }), _jsx("div", { className: classes.infoContent, children: (_a = snapshot.pool) !== null && _a !== void 0 ? _a : '-' })] }), _jsxs("div", { className: classes.infoBlock, children: [_jsx("div", { className: classes.header, children: "Number of clones" }), _jsx("div", { className: classes.infoContent, children: (_b = snapshot.numClones) !== null && _b !== void 0 ? _b : '-' })] }), _jsxs("div", { className: classes.infoBlock, children: [_jsx("div", { className: classes.header, children: "Logical Size" }), _jsx("div", { className: classes.infoContent, children: snapshot.logicalSize ? formatBytesIEC(snapshot.logicalSize) : '-' })] }), _jsxs("div", { className: classes.infoBlock, children: [_jsx("div", { className: classes.header, children: "Physical Size" }), _jsx("div", { className: classes.infoContent, children: snapshot.physicalSize
|
|
117
117
|
? formatBytesIEC(snapshot.physicalSize)
|
|
118
118
|
: '-' })] }), _jsxs("div", { className: classes.actionsContainer, onClick: (e) => e.stopPropagation(), children: [_jsx("div", { className: classes.snapshotId, children: snapshot.id }), _jsx("div", { className: classes.copyButtonContainer, title: "Copy snapshot ID", children: _jsx(IconButton, { className: classes.copyButton, onClick: (e) => {
|
|
119
119
|
e.stopPropagation();
|