@saltcorn/server 0.7.4 → 0.8.0-beta.0
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/app.js +18 -11
- package/auth/admin.js +173 -74
- package/auth/routes.js +40 -15
- package/locales/en.json +46 -3
- package/locales/es.json +134 -134
- package/locales/ru.json +32 -5
- package/markup/admin.js +40 -38
- package/markup/forms.js +4 -3
- package/package.json +8 -7
- package/public/diagram_utils.js +530 -0
- package/public/gridedit.js +4 -1
- package/public/jquery-menu-editor.min.js +112 -112
- package/public/saltcorn-common.js +31 -8
- package/public/saltcorn.css +11 -0
- package/public/saltcorn.js +211 -70
- package/restart_watcher.js +1 -0
- package/routes/actions.js +5 -1
- package/routes/admin.js +229 -79
- package/routes/api.js +19 -2
- package/routes/common_lists.js +137 -134
- package/routes/diagram.js +43 -117
- package/routes/fields.js +4 -1
- package/routes/files.js +137 -101
- package/routes/homepage.js +2 -2
- package/routes/infoarch.js +2 -2
- package/routes/list.js +4 -4
- package/routes/page.js +16 -3
- package/routes/pageedit.js +13 -8
- package/routes/scapi.js +1 -1
- package/routes/search.js +1 -1
- package/routes/tables.js +4 -5
- package/routes/tag_entries.js +31 -10
- package/routes/tags.js +10 -10
- package/routes/tenant.js +98 -36
- package/routes/utils.js +12 -0
- package/routes/view.js +0 -1
- package/routes/viewedit.js +45 -32
- package/serve.js +5 -0
- package/tests/admin.test.js +2 -0
- package/tests/auth.test.js +20 -0
- package/tests/files.test.js +11 -20
- package/tests/tenant.test.js +4 -2
package/app.js
CHANGED
|
@@ -122,12 +122,10 @@ const getApp = async (opts = {}) => {
|
|
|
122
122
|
app.use(passport.initialize());
|
|
123
123
|
app.use(passport.authenticate(["jwt", "session"]));
|
|
124
124
|
app.use((req, res, next) => {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
next();
|
|
130
|
-
});
|
|
125
|
+
// no jwt and session id at the same time
|
|
126
|
+
if (!(jwt_extractor(req) && req.cookies && req.cookies["connect.sid"]))
|
|
127
|
+
next();
|
|
128
|
+
});
|
|
131
129
|
app.use(flash());
|
|
132
130
|
|
|
133
131
|
//static serving
|
|
@@ -170,6 +168,15 @@ const getApp = async (opts = {}) => {
|
|
|
170
168
|
}
|
|
171
169
|
)
|
|
172
170
|
);
|
|
171
|
+
app.use(
|
|
172
|
+
`/static_assets/${version_tag}`,
|
|
173
|
+
express.static(
|
|
174
|
+
path.dirname(require.resolve("@saltcorn/filemanager/package.json")) + "/public/build",
|
|
175
|
+
{
|
|
176
|
+
maxAge: development_mode ? 0 : "100d",
|
|
177
|
+
}
|
|
178
|
+
)
|
|
179
|
+
);
|
|
173
180
|
|
|
174
181
|
passport.use(
|
|
175
182
|
"local",
|
|
@@ -248,7 +255,7 @@ const getApp = async (opts = {}) => {
|
|
|
248
255
|
};
|
|
249
256
|
if (
|
|
250
257
|
db.is_it_multi_tenant() &&
|
|
251
|
-
jwt_payload.tenant?.length > 0 &&
|
|
258
|
+
jwt_payload.tenant?.length > 0 &&
|
|
252
259
|
jwt_payload.tenant !== db.connectObj.default_schema
|
|
253
260
|
) {
|
|
254
261
|
return await db.runWithTenant(jwt_payload.tenant, userCheck);
|
|
@@ -341,13 +348,13 @@ Sitemap: ${base}sitemap.xml
|
|
|
341
348
|
<urlset
|
|
342
349
|
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
343
350
|
${urls
|
|
344
|
-
|
|
345
|
-
|
|
351
|
+
.map(
|
|
352
|
+
(url) => `<url>
|
|
346
353
|
<loc>${url}</loc>
|
|
347
354
|
<lastmod>${now}</lastmod>
|
|
348
355
|
</url>`
|
|
349
|
-
|
|
350
|
-
|
|
356
|
+
)
|
|
357
|
+
.join("")}
|
|
351
358
|
|
|
352
359
|
</urlset>`);
|
|
353
360
|
})
|
package/auth/admin.js
CHANGED
|
@@ -38,7 +38,9 @@ const {
|
|
|
38
38
|
is_hsts_tld,
|
|
39
39
|
} = require("../markup/admin");
|
|
40
40
|
const { send_verification_email } = require("@saltcorn/data/models/email");
|
|
41
|
-
|
|
41
|
+
const {
|
|
42
|
+
expressionValidator,
|
|
43
|
+
} = require("@saltcorn/data/models/expression");
|
|
42
44
|
/**
|
|
43
45
|
* @type {object}
|
|
44
46
|
* @const
|
|
@@ -177,33 +179,33 @@ const user_dropdown = (user, req, can_reset) =>
|
|
|
177
179
|
req
|
|
178
180
|
),
|
|
179
181
|
can_reset &&
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
182
|
+
post_dropdown_item(
|
|
183
|
+
`/useradmin/reset-password/${user.id}`,
|
|
184
|
+
'<i class="fas fa-envelope"></i> ' +
|
|
185
|
+
req.__("Send password reset email"),
|
|
186
|
+
req
|
|
187
|
+
),
|
|
186
188
|
can_reset &&
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
189
|
+
!user.verified_on &&
|
|
190
|
+
getState().getConfig("verification_view", "") &&
|
|
191
|
+
post_dropdown_item(
|
|
192
|
+
`/useradmin/send-verification/${user.id}`,
|
|
193
|
+
'<i class="fas fa-envelope"></i> ' +
|
|
194
|
+
req.__("Send verification email"),
|
|
195
|
+
req
|
|
196
|
+
),
|
|
195
197
|
user.disabled &&
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
198
|
+
post_dropdown_item(
|
|
199
|
+
`/useradmin/enable/${user.id}`,
|
|
200
|
+
'<i class="fas fa-play"></i> ' + req.__("Enable"),
|
|
201
|
+
req
|
|
202
|
+
),
|
|
201
203
|
!user.disabled &&
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
204
|
+
post_dropdown_item(
|
|
205
|
+
`/useradmin/disable/${user.id}`,
|
|
206
|
+
'<i class="fas fa-pause"></i> ' + req.__("Disable"),
|
|
207
|
+
req
|
|
208
|
+
),
|
|
207
209
|
div({ class: "dropdown-divider" }),
|
|
208
210
|
post_dropdown_item(
|
|
209
211
|
`/useradmin/delete/${user.id}`,
|
|
@@ -257,8 +259,8 @@ router.get(
|
|
|
257
259
|
key: (r) =>
|
|
258
260
|
!!r.verified_on
|
|
259
261
|
? i({
|
|
260
|
-
|
|
261
|
-
|
|
262
|
+
class: "fas fa-check-circle text-success",
|
|
263
|
+
})
|
|
262
264
|
: "",
|
|
263
265
|
},
|
|
264
266
|
{ label: req.__("Role"), key: (r) => roleMap[r.role_id] },
|
|
@@ -421,15 +423,15 @@ router.get(
|
|
|
421
423
|
above: [
|
|
422
424
|
...(letsencrypt && has_custom
|
|
423
425
|
? [
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
426
|
+
{
|
|
427
|
+
type: "card",
|
|
428
|
+
contents: p(
|
|
429
|
+
req.__(
|
|
430
|
+
"You have enabled both Let's Encrypt certificates and custom SSL certificates. Let's Encrypt takes priority and the custom certificates will be ignored."
|
|
431
|
+
)
|
|
432
|
+
),
|
|
433
|
+
},
|
|
434
|
+
]
|
|
433
435
|
: []),
|
|
434
436
|
{
|
|
435
437
|
type: "card",
|
|
@@ -450,33 +452,33 @@ router.get(
|
|
|
450
452
|
),
|
|
451
453
|
letsencrypt
|
|
452
454
|
? post_btn(
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
455
|
+
"/config/delete/letsencrypt",
|
|
456
|
+
req.__("Disable LetsEncrypt HTTPS"),
|
|
457
|
+
req.csrfToken(),
|
|
458
|
+
{ btnClass: "btn-danger", req }
|
|
459
|
+
)
|
|
458
460
|
: post_btn(
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
461
|
+
"/admin/enable-letsencrypt",
|
|
462
|
+
req.__("Enable LetsEncrypt HTTPS"),
|
|
463
|
+
req.csrfToken(),
|
|
464
|
+
{ confirm: true, req }
|
|
465
|
+
),
|
|
464
466
|
!letsencrypt &&
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
)
|
|
473
|
-
),
|
|
474
|
-
p(
|
|
475
|
-
req.__(
|
|
476
|
-
"The DNS A records (for * and @, or a subdomain) should point to this server's IP address before enabling LetsEncrypt"
|
|
477
|
-
)
|
|
467
|
+
show_warning &&
|
|
468
|
+
!has_custom &&
|
|
469
|
+
div(
|
|
470
|
+
{ class: "mt-3 alert alert-danger" },
|
|
471
|
+
p(
|
|
472
|
+
req.__(
|
|
473
|
+
"The address you are using to reach Saltcorn does not match the Base URL."
|
|
478
474
|
)
|
|
479
475
|
),
|
|
476
|
+
p(
|
|
477
|
+
req.__(
|
|
478
|
+
"The DNS A records (for * and @, or a subdomain) should point to this server's IP address before enabling LetsEncrypt"
|
|
479
|
+
)
|
|
480
|
+
)
|
|
481
|
+
),
|
|
480
482
|
],
|
|
481
483
|
},
|
|
482
484
|
{
|
|
@@ -570,8 +572,8 @@ router.post(
|
|
|
570
572
|
req.flash(
|
|
571
573
|
"success",
|
|
572
574
|
req.__("Custom SSL enabled. Restart for changes to take effect.") +
|
|
573
|
-
|
|
574
|
-
|
|
575
|
+
" " +
|
|
576
|
+
a({ href: "/admin/system" }, req.__("Restart here"))
|
|
575
577
|
);
|
|
576
578
|
if (!req.xhr) {
|
|
577
579
|
res.redirect("/useradmin/ssl");
|
|
@@ -580,6 +582,103 @@ router.post(
|
|
|
580
582
|
})
|
|
581
583
|
);
|
|
582
584
|
|
|
585
|
+
/**
|
|
586
|
+
* @name get/ssl/custom
|
|
587
|
+
* @function
|
|
588
|
+
* @memberof module:auth/admin~auth/adminRouter
|
|
589
|
+
*/
|
|
590
|
+
router.get(
|
|
591
|
+
"/table-access",
|
|
592
|
+
isAdmin,
|
|
593
|
+
error_catcher(async (req, res) => {
|
|
594
|
+
const tables = await Table.find()
|
|
595
|
+
const roleOptions = (await User.get_roles()).map((r) => ({
|
|
596
|
+
value: r.id,
|
|
597
|
+
label: r.role,
|
|
598
|
+
}));
|
|
599
|
+
|
|
600
|
+
const contents = []
|
|
601
|
+
for (const table of tables) {
|
|
602
|
+
if (table.external) continue
|
|
603
|
+
const fields = await table.getFields();
|
|
604
|
+
const userFields = fields
|
|
605
|
+
.filter((f) => f.reftable_name === "users")
|
|
606
|
+
.map((f) => ({ value: f.id, label: f.name }));
|
|
607
|
+
const form = new Form({
|
|
608
|
+
action: "/table",
|
|
609
|
+
noSubmitButton: true,
|
|
610
|
+
onChange: "saveAndContinue(this)",
|
|
611
|
+
fields: [
|
|
612
|
+
{
|
|
613
|
+
label: req.__("Ownership field"),
|
|
614
|
+
name: "ownership_field_id",
|
|
615
|
+
sublabel: req.__(
|
|
616
|
+
"The user referred to in this field will be the owner of the row"
|
|
617
|
+
),
|
|
618
|
+
input_type: "select",
|
|
619
|
+
options: [
|
|
620
|
+
{ value: "", label: req.__("None") },
|
|
621
|
+
...userFields,
|
|
622
|
+
{ value: "_formula", label: req.__("Formula") },
|
|
623
|
+
],
|
|
624
|
+
},
|
|
625
|
+
{
|
|
626
|
+
name: "ownership_formula",
|
|
627
|
+
label: req.__("Ownership formula"),
|
|
628
|
+
validator: expressionValidator,
|
|
629
|
+
type: "String",
|
|
630
|
+
class: "validate-expression",
|
|
631
|
+
sublabel:
|
|
632
|
+
req.__("User is treated as owner if true. In scope: ") +
|
|
633
|
+
["user", ...fields.map((f) => f.name)]
|
|
634
|
+
.map((fn) => code(fn))
|
|
635
|
+
.join(", "),
|
|
636
|
+
showIf: { ownership_field_id: "_formula" },
|
|
637
|
+
},
|
|
638
|
+
{
|
|
639
|
+
label: req.__("Minimum role to read"),
|
|
640
|
+
sublabel: req.__(
|
|
641
|
+
"User must have this role or higher to read rows from the table, unless they are the owner"
|
|
642
|
+
),
|
|
643
|
+
name: "min_role_read",
|
|
644
|
+
input_type: "select",
|
|
645
|
+
options: roleOptions,
|
|
646
|
+
attributes: { asideNext: true }
|
|
647
|
+
},
|
|
648
|
+
{
|
|
649
|
+
label: req.__("Minimum role to write"),
|
|
650
|
+
name: "min_role_write",
|
|
651
|
+
input_type: "select",
|
|
652
|
+
sublabel: req.__(
|
|
653
|
+
"User must have this role or higher to edit or create new rows in the table, unless they are the owner"
|
|
654
|
+
),
|
|
655
|
+
options: roleOptions,
|
|
656
|
+
},
|
|
657
|
+
]
|
|
658
|
+
})
|
|
659
|
+
form.hidden("id", "name");
|
|
660
|
+
form.values = table
|
|
661
|
+
if (table.ownership_formula && !table.ownership_field_id)
|
|
662
|
+
form.values.ownership_field_id = "_formula";
|
|
663
|
+
contents.push(div(
|
|
664
|
+
h5(a({ href: `/table/${table.id}` }, table.name)),
|
|
665
|
+
renderForm(form, req.csrfToken())
|
|
666
|
+
))
|
|
667
|
+
}
|
|
668
|
+
send_users_page({
|
|
669
|
+
res,
|
|
670
|
+
req,
|
|
671
|
+
active_sub: "Table access",
|
|
672
|
+
contents: {
|
|
673
|
+
type: "card",
|
|
674
|
+
title: req.__("Table access"),
|
|
675
|
+
contents
|
|
676
|
+
},
|
|
677
|
+
});
|
|
678
|
+
})
|
|
679
|
+
);
|
|
680
|
+
|
|
681
|
+
|
|
583
682
|
/**
|
|
584
683
|
* @name get/:id
|
|
585
684
|
* @function
|
|
@@ -613,9 +712,9 @@ router.get(
|
|
|
613
712
|
div(
|
|
614
713
|
user.api_token
|
|
615
714
|
? span(
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
715
|
+
{ class: "me-1" },
|
|
716
|
+
req.__("API token for this user: ")
|
|
717
|
+
) + code(user.api_token)
|
|
619
718
|
: req.__("No API token issued")
|
|
620
719
|
),
|
|
621
720
|
// button for reset or generate api token
|
|
@@ -629,16 +728,16 @@ router.get(
|
|
|
629
728
|
),
|
|
630
729
|
// button for remove api token
|
|
631
730
|
user.api_token &&
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
731
|
+
div(
|
|
732
|
+
{ class: "mt-4 ms-2 d-inline-block" },
|
|
733
|
+
post_btn(
|
|
734
|
+
`/useradmin/remove-api-token/${user.id}`,
|
|
735
|
+
// TBD localization
|
|
736
|
+
user.api_token ? req.__("Remove") : req.__("Generate"),
|
|
737
|
+
req.csrfToken(),
|
|
738
|
+
{ req: req, confirm: true }
|
|
739
|
+
)
|
|
740
|
+
),
|
|
642
741
|
],
|
|
643
742
|
},
|
|
644
743
|
],
|
package/auth/routes.js
CHANGED
|
@@ -201,32 +201,57 @@ const getAuthLinks = (current, noMethods) => {
|
|
|
201
201
|
|
|
202
202
|
const loginWithJwt = async (email, password, saltcornApp, res) => {
|
|
203
203
|
const loginFn = async () => {
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
204
|
+
const publicUserLink = getState().getConfig("public_user_link");
|
|
205
|
+
const jwt_secret = db.connectObj.jwt_secret;
|
|
206
|
+
if (email && password) {
|
|
207
|
+
// with credentials
|
|
208
|
+
const user = await User.findOne({ email });
|
|
209
|
+
if (user && user.checkPassword(password)) {
|
|
210
|
+
const now = new Date();
|
|
211
|
+
const token = jwt.sign(
|
|
212
|
+
{
|
|
213
|
+
sub: email,
|
|
214
|
+
user: {
|
|
215
|
+
id: user.id,
|
|
216
|
+
email: user.email,
|
|
217
|
+
role_id: user.role_id,
|
|
218
|
+
language: user.language ? user.language : "en",
|
|
219
|
+
disabled: user.disabled,
|
|
220
|
+
},
|
|
221
|
+
iss: "saltcorn@saltcorn",
|
|
222
|
+
aud: "saltcorn-mobile-app",
|
|
223
|
+
iat: now.valueOf(),
|
|
224
|
+
tenant: db.getTenantSchema(),
|
|
225
|
+
},
|
|
226
|
+
jwt_secret
|
|
227
|
+
);
|
|
228
|
+
if (!user.last_mobile_login) await user.updateLastMobileLogin(now);
|
|
229
|
+
res.json(token);
|
|
230
|
+
} else {
|
|
231
|
+
res.json({
|
|
232
|
+
alerts: [{ type: "danger", msg: "Incorrect user or password" }],
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
} else if (publicUserLink) {
|
|
236
|
+
// public login
|
|
208
237
|
const token = jwt.sign(
|
|
209
238
|
{
|
|
210
|
-
sub:
|
|
239
|
+
sub: "public",
|
|
211
240
|
user: {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
role_id: user.role_id,
|
|
215
|
-
language: user.language ? user.language : "en",
|
|
216
|
-
disabled: user.disabled,
|
|
241
|
+
role_id: 10,
|
|
242
|
+
language: "en",
|
|
217
243
|
},
|
|
218
244
|
iss: "saltcorn@saltcorn",
|
|
219
245
|
aud: "saltcorn-mobile-app",
|
|
220
|
-
iat:
|
|
246
|
+
iat: new Date().valueOf(),
|
|
221
247
|
tenant: db.getTenantSchema(),
|
|
222
248
|
},
|
|
223
249
|
jwt_secret
|
|
224
250
|
);
|
|
225
|
-
if (!user.last_mobile_login) await user.updateLastMobileLogin(now);
|
|
226
251
|
res.json(token);
|
|
227
252
|
} else {
|
|
228
253
|
res.json({
|
|
229
|
-
alerts: [{ type: "danger", msg: "
|
|
254
|
+
alerts: [{ type: "danger", msg: "The public login is deactivated" }],
|
|
230
255
|
});
|
|
231
256
|
}
|
|
232
257
|
};
|
|
@@ -1158,7 +1183,7 @@ const setLanguageForm = (req, user) =>
|
|
|
1158
1183
|
option(
|
|
1159
1184
|
{
|
|
1160
1185
|
value: locale,
|
|
1161
|
-
...(user && user.language === locale && { selected: true }),
|
|
1186
|
+
...(((user && user.language === locale) || (user && !user.language && req.getLocale() === locale)) && { selected: true }),
|
|
1162
1187
|
},
|
|
1163
1188
|
language
|
|
1164
1189
|
)
|
|
@@ -1382,7 +1407,7 @@ router.get(
|
|
|
1382
1407
|
return;
|
|
1383
1408
|
}
|
|
1384
1409
|
res.sendWrap(
|
|
1385
|
-
req.__("User settings"),
|
|
1410
|
+
req.__("User settings") || "User settings",
|
|
1386
1411
|
await userSettings({ req, res, pwform: changPwForm(req), user })
|
|
1387
1412
|
);
|
|
1388
1413
|
})
|
package/locales/en.json
CHANGED
|
@@ -991,6 +991,49 @@
|
|
|
991
991
|
"Add triggers": "Add triggers",
|
|
992
992
|
"Formula value": "Formula value",
|
|
993
993
|
"The build was successfully": "The build was successfully",
|
|
994
|
-
"Unable to build the app
|
|
995
|
-
"Add tag": "Add tag"
|
|
996
|
-
|
|
994
|
+
"Unable to build the app": "Unable to build the app",
|
|
995
|
+
"Add tag": "Add tag",
|
|
996
|
+
"Create new row": "Create new row",
|
|
997
|
+
"Specify how to create a new row": "Specify how to create a new row",
|
|
998
|
+
"Preview": "Preview",
|
|
999
|
+
"Minimum role updated": "Minimum role updated",
|
|
1000
|
+
"Module not found": "Module not found",
|
|
1001
|
+
"View %s not found": "View %s not found",
|
|
1002
|
+
"Query %s not found": "Query %s not found",
|
|
1003
|
+
"Open": "Open",
|
|
1004
|
+
"Only the android build supports docker.": "Only the android build supports docker.",
|
|
1005
|
+
"Please enter a valid server URL.": "Please enter a valid server URL.",
|
|
1006
|
+
"Table access": "Table access",
|
|
1007
|
+
"Download one of the backups above": "Download one of the backups above",
|
|
1008
|
+
"Clear this application": "Clear this application",
|
|
1009
|
+
"(tick all boxes)": "(tick all boxes)",
|
|
1010
|
+
"When prompted to create the first user, click the link to restore a backup": "When prompted to create the first user, click the link to restore a backup",
|
|
1011
|
+
"Select the downloaded backup file": "Select the downloaded backup file",
|
|
1012
|
+
"Units": "Units",
|
|
1013
|
+
"Descending?": "Descending?",
|
|
1014
|
+
"Small": "Small",
|
|
1015
|
+
"Medium": "Medium",
|
|
1016
|
+
"Large": "Large",
|
|
1017
|
+
"Extra-large": "Extra-large",
|
|
1018
|
+
"Please select at least one item": "Please select at least one item",
|
|
1019
|
+
"Only include rows where this formula is true. ": "Only include rows where this formula is true. ",
|
|
1020
|
+
"Use %s to access current user ID": "Use %s to access current user ID",
|
|
1021
|
+
"Action not found": "Action not found",
|
|
1022
|
+
"Development settings": "Development settings",
|
|
1023
|
+
"All entities": "All entities",
|
|
1024
|
+
"no tags": "no tags",
|
|
1025
|
+
"Development mode settings updated": "Development mode settings updated",
|
|
1026
|
+
"Locale identifier short code, e.g. en, zh, fr, ar etc. ": "Locale identifier short code, e.g. en, zh, fr, ar etc. ",
|
|
1027
|
+
"Is this the default language in which the application is built?": "Is this the default language in which the application is built?",
|
|
1028
|
+
"Database type": "Database type",
|
|
1029
|
+
"Database schema name": "Database schema name",
|
|
1030
|
+
"Database user": "Database user",
|
|
1031
|
+
"Database host": "Database host",
|
|
1032
|
+
"Database port": "Database port",
|
|
1033
|
+
"Creator email": "Creator email",
|
|
1034
|
+
"Create tenant warning text": "Create tenant warning text",
|
|
1035
|
+
"Provide your own create warning text if need": "Provide your own create warning text if need",
|
|
1036
|
+
"Specify some description for tenant if need": "Specify some description for tenant if need",
|
|
1037
|
+
"Created": "Created",
|
|
1038
|
+
"First user E-mail": "First user E-mail"
|
|
1039
|
+
}
|