shutro-erp 0.3.2 → 0.3.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/dist/account_portal/.kosh/bindings.js +1 -1
- package/dist/account_portal/.kosh/schema.d.ts +156 -1
- package/dist/accounting/.kosh/bindings.js +1 -1
- package/dist/accounting/.kosh/schema.d.ts +156 -1
- package/dist/assistant/index.js +1 -1
- package/dist/contacts/.kosh/bindings.js +1 -1
- package/dist/contacts/.kosh/schema.d.ts +156 -1
- package/dist/integrations/index.js +12 -0
- package/dist/integrations/web/OAuthAppsPage.d.ts +9 -0
- package/dist/integrations/web/OAuthAppsPage.js +79 -0
- package/dist/integrations/web/index.d.ts +1 -0
- package/dist/integrations/web/index.js +3 -0
- package/dist/integrations/web/messages.js +58 -0
- package/dist/l10n_bd/.kosh/bindings.js +1 -1
- package/dist/l10n_bd/.kosh/schema.d.ts +156 -1
- package/dist/l10n_in/.kosh/bindings.js +1 -1
- package/dist/l10n_in/.kosh/schema.d.ts +156 -4
- package/dist/l10n_in/module.d.ts +0 -62
- package/dist/l10n_in/module.js +2 -4
- package/dist/messaging/web/index.js +1 -1
- package/dist/notify/web/index.js +1 -1
- package/dist/payment/.kosh/bindings.js +1 -1
- package/dist/payment/.kosh/schema.d.ts +157 -2
- package/dist/payment/bkash.d.ts +28 -0
- package/dist/payment/bkash.js +169 -0
- package/dist/payment/index.d.ts +4 -0
- package/dist/payment/index.js +80 -24
- package/dist/payment/module.d.ts +7 -4
- package/dist/payment/module.js +3 -0
- package/dist/payment/money.d.ts +7 -0
- package/dist/payment/money.js +37 -0
- package/dist/payment/providers.d.ts +13 -2
- package/dist/payment/razorpay.d.ts +12 -0
- package/dist/payment/razorpay.js +149 -0
- package/dist/payment/sslcommerz.js +1 -1
- package/dist/payment/stripe.d.ts +15 -0
- package/dist/payment/stripe.js +182 -0
- package/dist/permissions/admin.d.ts +3 -0
- package/dist/permissions/admin.js +108 -10
- package/dist/permissions/index.d.ts +1 -0
- package/dist/permissions/index.js +3 -0
- package/dist/permissions/roles.d.ts +2 -0
- package/dist/permissions/roles.js +236 -0
- package/dist/portal/.kosh/bindings.js +1 -1
- package/dist/portal/.kosh/schema.d.ts +156 -1
- package/dist/product/.kosh/bindings.js +1 -1
- package/dist/product/.kosh/schema.d.ts +156 -1
- package/dist/project/.kosh/bindings.js +1 -1
- package/dist/project/.kosh/schema.d.ts +156 -1
- package/dist/project_portal/.kosh/bindings.js +1 -1
- package/dist/project_portal/.kosh/schema.d.ts +156 -1
- package/dist/purchase/.kosh/bindings.js +1 -1
- package/dist/purchase/.kosh/schema.d.ts +156 -1
- package/dist/purchase_account/.kosh/bindings.js +1 -1
- package/dist/purchase_account/.kosh/schema.d.ts +156 -1
- package/dist/purchase_portal/.kosh/bindings.js +1 -1
- package/dist/purchase_portal/.kosh/schema.d.ts +156 -1
- package/dist/sale_account/.kosh/bindings.js +1 -1
- package/dist/sale_account/.kosh/schema.d.ts +156 -1
- package/dist/sale_portal/.kosh/bindings.js +1 -1
- package/dist/sale_portal/.kosh/schema.d.ts +156 -1
- package/dist/sale_project/.kosh/bindings.js +1 -1
- package/dist/sale_project/.kosh/schema.d.ts +156 -1
- package/dist/sales/.kosh/bindings.js +1 -1
- package/dist/sales/.kosh/schema.d.ts +156 -1
- package/dist/server/auth/base.js +98 -0
- package/dist/server/auth/oauth.d.ts +21 -0
- package/dist/server/auth/oauth.js +579 -0
- package/dist/server/auth/routes.d.ts +3 -0
- package/dist/server/auth/routes.js +29 -0
- package/dist/server/auth/service.d.ts +56 -0
- package/dist/server/auth/service.js +185 -3
- package/dist/server/identity.d.ts +4 -0
- package/dist/server/images.d.ts +12 -0
- package/dist/server/images.js +139 -0
- package/dist/server/index.d.ts +2 -1
- package/dist/server/index.js +1 -0
- package/dist/server/server.d.ts +4 -0
- package/dist/server/server.js +20 -4
- package/dist/settings/company.d.ts +34 -0
- package/dist/settings/company.js +189 -0
- package/dist/settings/index.d.ts +10 -10
- package/dist/settings/index.js +159 -30
- package/dist/settings/people.d.ts +16 -0
- package/dist/settings/people.js +507 -0
- package/dist/settings/security.d.ts +13 -0
- package/dist/settings/security.js +158 -0
- package/dist/settings/web/AuditPage.d.ts +8 -0
- package/dist/settings/web/AuditPage.js +74 -0
- package/dist/settings/web/CompaniesPage.d.ts +8 -0
- package/dist/settings/web/CompaniesPage.js +52 -0
- package/dist/settings/web/CompanyPage.d.ts +9 -0
- package/dist/settings/web/CompanyPage.js +105 -0
- package/dist/settings/web/ConnectedAppsPage.d.ts +7 -0
- package/dist/settings/web/ConnectedAppsPage.js +33 -0
- package/dist/settings/web/OverviewPage.d.ts +9 -0
- package/dist/settings/web/OverviewPage.js +77 -0
- package/dist/settings/web/PeoplePage.d.ts +9 -0
- package/dist/settings/web/PeoplePage.js +154 -0
- package/dist/settings/web/ProfilePage.d.ts +14 -0
- package/dist/settings/web/ProfilePage.js +196 -0
- package/dist/settings/web/RolesEditor.d.ts +35 -0
- package/dist/settings/web/RolesEditor.js +49 -0
- package/dist/settings/web/RolesPage.d.ts +9 -0
- package/dist/settings/web/RolesPage.js +296 -0
- package/dist/settings/web/SecurityPage.d.ts +8 -0
- package/dist/settings/web/SecurityPage.js +81 -0
- package/dist/settings/web/index.d.ts +10 -0
- package/dist/settings/web/index.js +31 -1
- package/dist/settings/web/messages.js +594 -0
- package/dist/ui/api.d.ts +8 -0
- package/dist/ui/app.d.ts +5 -0
- package/dist/ui/app.js +143 -33
- package/dist/ui/components/AppIcon.js +11 -1
- package/dist/ui/components/Avatar.d.ts +21 -0
- package/dist/ui/components/Avatar.js +71 -0
- package/dist/ui/components/primitives.d.ts +9 -1
- package/dist/ui/components/primitives.js +12 -4
- package/dist/ui/context.d.ts +10 -1
- package/dist/ui/context.js +60 -2
- package/dist/ui/i18n/messages.d.ts +76 -0
- package/dist/ui/i18n/messages.js +152 -0
- package/dist/ui/index.d.ts +3 -1
- package/dist/ui/index.js +3 -1
- package/dist/ui/lib/accent.d.ts +13 -0
- package/dist/ui/lib/accent.js +36 -0
- package/dist/ui/registry.d.ts +7 -1
- package/dist/ui/registry.js +10 -1
- package/dist/ui/search/ViewTabs.d.ts +14 -0
- package/dist/ui/search/ViewTabs.js +42 -0
- package/dist/ui/shell/Activate.d.ts +6 -0
- package/dist/ui/shell/Activate.js +39 -0
- package/dist/ui/shell/CommandPalette.d.ts +7 -1
- package/dist/ui/shell/CommandPalette.js +16 -2
- package/dist/ui/shell/Consent.d.ts +5 -0
- package/dist/ui/shell/Consent.js +35 -0
- package/dist/ui/shell/Home.js +85 -16
- package/dist/ui/shell/Sidebar.d.ts +27 -0
- package/dist/ui/shell/Sidebar.js +77 -0
- package/dist/ui/shell/TwoFactorSetup.d.ts +5 -0
- package/dist/ui/shell/TwoFactorSetup.js +32 -0
- package/dist/ui/shell/shortcuts.d.ts +3 -0
- package/dist/ui/shell/shortcuts.js +13 -4
- package/dist/ui/styles.css +70 -28
- package/dist/ui/views/DateField.d.ts +10 -0
- package/dist/ui/views/DateField.js +129 -0
- package/dist/ui/views/FormView.js +161 -21
- package/dist/ui/views/ListView.d.ts +2 -0
- package/dist/ui/views/ListView.js +57 -25
- package/dist/ui/views/StatusChip.d.ts +10 -0
- package/dist/ui/views/StatusChip.js +22 -0
- package/dist/ui/views/widgets.d.ts +3 -0
- package/dist/ui/views/widgets.js +26 -8
- package/dist/views/types.d.ts +7 -0
- package/dist/views/validate.js +4 -0
- package/package.json +2 -2
package/dist/ui/context.js
CHANGED
|
@@ -4,6 +4,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
4
4
|
* formatter for the user's language and time zone, and the theme.
|
|
5
5
|
*/
|
|
6
6
|
import { createContext, useContext, useEffect, useMemo, useState, } from 'react';
|
|
7
|
+
import { accentVariables } from './lib/accent.js';
|
|
7
8
|
import { createFormatter } from './lib/format.js';
|
|
8
9
|
const Context = createContext(null);
|
|
9
10
|
/** The renderer context. @throws outside {@link KoshProvider} */
|
|
@@ -14,6 +15,45 @@ export function useKosh() {
|
|
|
14
15
|
return value;
|
|
15
16
|
}
|
|
16
17
|
const THEME_KEY = 'kosh.theme';
|
|
18
|
+
const DENSITY_KEY = 'kosh.density';
|
|
19
|
+
function readDensity() {
|
|
20
|
+
try {
|
|
21
|
+
return JSON.parse(localStorage.getItem(DENSITY_KEY) ?? 'null') === 'compact'
|
|
22
|
+
? 'compact'
|
|
23
|
+
: 'comfortable';
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return 'comfortable';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/** Applies the density to `<html>` (`data-density`), remembered per browser. */
|
|
30
|
+
function useDensity() {
|
|
31
|
+
const [density, setDensity] = useState(readDensity);
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
document.documentElement.dataset['density'] = density;
|
|
34
|
+
try {
|
|
35
|
+
localStorage.setItem(DENSITY_KEY, JSON.stringify(density));
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// storage unavailable: the choice lasts for this page only
|
|
39
|
+
}
|
|
40
|
+
}, [density]);
|
|
41
|
+
return [density, setDensity];
|
|
42
|
+
}
|
|
43
|
+
/** Sets the company's brand colour as the accent (RFC 0018), or the default when it has none. */
|
|
44
|
+
function useAccent(accent) {
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
const root = document.documentElement.style;
|
|
47
|
+
const variables = accentVariables(accent);
|
|
48
|
+
for (const key of ['--accent-h', '--accent-c']) {
|
|
49
|
+
const value = variables[key];
|
|
50
|
+
if (value === undefined)
|
|
51
|
+
root.removeProperty(key);
|
|
52
|
+
else
|
|
53
|
+
root.setProperty(key, value);
|
|
54
|
+
}
|
|
55
|
+
}, [accent]);
|
|
56
|
+
}
|
|
17
57
|
function readTheme() {
|
|
18
58
|
try {
|
|
19
59
|
const stored = localStorage.getItem(THEME_KEY);
|
|
@@ -47,8 +87,10 @@ function useTheme() {
|
|
|
47
87
|
}, [theme]);
|
|
48
88
|
return [theme, setTheme];
|
|
49
89
|
}
|
|
50
|
-
export function KoshProvider({ api, registry, uid, companyId, lang, tz, grouping, realtime, offline, children, }) {
|
|
90
|
+
export function KoshProvider({ api, registry, uid, companyId, lang, tz, grouping, accent, realtime, offline, switchCompany, children, }) {
|
|
51
91
|
const [theme, setTheme] = useTheme();
|
|
92
|
+
const [density, setDensity] = useDensity();
|
|
93
|
+
useAccent(accent);
|
|
52
94
|
const format = useMemo(() => createFormatter(lang, tz, grouping === undefined ? {} : { grouping }), [lang, tz, grouping]);
|
|
53
95
|
const value = useMemo(() => ({
|
|
54
96
|
api,
|
|
@@ -58,9 +100,25 @@ export function KoshProvider({ api, registry, uid, companyId, lang, tz, grouping
|
|
|
58
100
|
format,
|
|
59
101
|
theme,
|
|
60
102
|
setTheme,
|
|
103
|
+
density,
|
|
104
|
+
setDensity,
|
|
61
105
|
...(realtime === undefined ? {} : { realtime }),
|
|
62
106
|
...(offline === undefined ? {} : { offline }),
|
|
63
|
-
|
|
107
|
+
...(switchCompany === undefined ? {} : { switchCompany }),
|
|
108
|
+
}), [
|
|
109
|
+
api,
|
|
110
|
+
registry,
|
|
111
|
+
uid,
|
|
112
|
+
companyId,
|
|
113
|
+
format,
|
|
114
|
+
theme,
|
|
115
|
+
setTheme,
|
|
116
|
+
density,
|
|
117
|
+
setDensity,
|
|
118
|
+
realtime,
|
|
119
|
+
offline,
|
|
120
|
+
switchCompany,
|
|
121
|
+
]);
|
|
64
122
|
return _jsx(Context.Provider, { value: value, children: children });
|
|
65
123
|
}
|
|
66
124
|
/** Theme switching without a signed-in user (the sign-in page). */
|
|
@@ -12,6 +12,14 @@ export declare const en: {
|
|
|
12
12
|
unknownPage: string;
|
|
13
13
|
};
|
|
14
14
|
auth: {
|
|
15
|
+
activateTitle: string;
|
|
16
|
+
activateIntro: string;
|
|
17
|
+
activateNoToken: string;
|
|
18
|
+
newPassword: string;
|
|
19
|
+
repeatPassword: string;
|
|
20
|
+
passwordRule: string;
|
|
21
|
+
mismatch: string;
|
|
22
|
+
activate: string;
|
|
15
23
|
signIn: string;
|
|
16
24
|
login: string;
|
|
17
25
|
password: string;
|
|
@@ -21,11 +29,32 @@ export declare const en: {
|
|
|
21
29
|
signOut: string;
|
|
22
30
|
invalid: string;
|
|
23
31
|
adminNeeds2fa: string;
|
|
32
|
+
setupTitle: string;
|
|
33
|
+
setupIntro: string;
|
|
34
|
+
setupStart: string;
|
|
35
|
+
setupStep1: string;
|
|
36
|
+
setupOpenApp: string;
|
|
37
|
+
setupStep2: string;
|
|
38
|
+
setupStep3: string;
|
|
39
|
+
setupTurnOn: string;
|
|
40
|
+
setupCodes: string;
|
|
41
|
+
setupContinue: string;
|
|
24
42
|
};
|
|
25
43
|
shell: {
|
|
26
44
|
apps: string;
|
|
27
45
|
menu: string;
|
|
28
46
|
theme: string;
|
|
47
|
+
density: string;
|
|
48
|
+
home: string;
|
|
49
|
+
appNamed: string;
|
|
50
|
+
switchCompany: string;
|
|
51
|
+
sidebar: string;
|
|
52
|
+
collapseSidebar: string;
|
|
53
|
+
expandSidebar: string;
|
|
54
|
+
openMenu: string;
|
|
55
|
+
closeMenu: string;
|
|
56
|
+
menuHint: string;
|
|
57
|
+
location: string;
|
|
29
58
|
light: string;
|
|
30
59
|
dark: string;
|
|
31
60
|
system: string;
|
|
@@ -62,6 +91,20 @@ export declare const en: {
|
|
|
62
91
|
exportFailed: string;
|
|
63
92
|
columns: string;
|
|
64
93
|
density: string;
|
|
94
|
+
statusOf: string;
|
|
95
|
+
nextState: string;
|
|
96
|
+
recordActions: string;
|
|
97
|
+
summary: string;
|
|
98
|
+
details: string;
|
|
99
|
+
recordPanel: string;
|
|
100
|
+
showPanel: string;
|
|
101
|
+
hidePanel: string;
|
|
102
|
+
previousMonth: string;
|
|
103
|
+
nextMonth: string;
|
|
104
|
+
pickDate: string;
|
|
105
|
+
datePlaceholder: string;
|
|
106
|
+
today: string;
|
|
107
|
+
clear: string;
|
|
65
108
|
proposed: string;
|
|
66
109
|
design: {
|
|
67
110
|
addField: string;
|
|
@@ -70,6 +113,7 @@ export declare const en: {
|
|
|
70
113
|
compact: string;
|
|
71
114
|
comfortable: string;
|
|
72
115
|
emptyTitle: string;
|
|
116
|
+
emptyNamed: string;
|
|
73
117
|
emptyHint: string;
|
|
74
118
|
emptyFiltered: string;
|
|
75
119
|
moved: string;
|
|
@@ -191,12 +235,38 @@ export declare const en: {
|
|
|
191
235
|
done: string;
|
|
192
236
|
recent: string;
|
|
193
237
|
apps: string;
|
|
238
|
+
today: string;
|
|
239
|
+
approve: string;
|
|
240
|
+
review: string;
|
|
241
|
+
dueToday: string;
|
|
242
|
+
mentioned: string;
|
|
243
|
+
saved: string;
|
|
194
244
|
};
|
|
195
245
|
toast: {
|
|
196
246
|
region: string;
|
|
197
247
|
close: string;
|
|
198
248
|
};
|
|
249
|
+
image: {
|
|
250
|
+
choosePhoto: string;
|
|
251
|
+
chooseLogo: string;
|
|
252
|
+
remove: string;
|
|
253
|
+
hint: string;
|
|
254
|
+
unreadable: string;
|
|
255
|
+
};
|
|
256
|
+
oauth: {
|
|
257
|
+
title: string;
|
|
258
|
+
as: string;
|
|
259
|
+
may: string;
|
|
260
|
+
limits: string;
|
|
261
|
+
back: string;
|
|
262
|
+
homepage: string;
|
|
263
|
+
already: string;
|
|
264
|
+
allow: string;
|
|
265
|
+
cancel: string;
|
|
266
|
+
};
|
|
199
267
|
palette: {
|
|
268
|
+
switchCompany: string;
|
|
269
|
+
profile: string;
|
|
200
270
|
button: string;
|
|
201
271
|
title: string;
|
|
202
272
|
description: string;
|
|
@@ -220,6 +290,7 @@ export declare const en: {
|
|
|
220
290
|
shortcuts: {
|
|
221
291
|
title: string;
|
|
222
292
|
palette: string;
|
|
293
|
+
sidebar: string;
|
|
223
294
|
search: string;
|
|
224
295
|
new: string;
|
|
225
296
|
views: string;
|
|
@@ -246,6 +317,11 @@ export declare const en: {
|
|
|
246
317
|
custom: string;
|
|
247
318
|
remove: string;
|
|
248
319
|
or: string;
|
|
320
|
+
savedViews: string;
|
|
321
|
+
allRecords: string;
|
|
322
|
+
moreViews_one: string;
|
|
323
|
+
moreViews_other: string;
|
|
324
|
+
shared: string;
|
|
249
325
|
};
|
|
250
326
|
};
|
|
251
327
|
type Messages = typeof en;
|
package/dist/ui/i18n/messages.js
CHANGED
|
@@ -12,6 +12,14 @@ export const en = {
|
|
|
12
12
|
unknownPage: 'The page "{{page}}" is not part of this app. Register it with registry.registerPage.',
|
|
13
13
|
},
|
|
14
14
|
auth: {
|
|
15
|
+
activateTitle: 'Choose your password',
|
|
16
|
+
activateIntro: 'You were invited to Shutro ERP. Choose a password to start.',
|
|
17
|
+
activateNoToken: 'This link is incomplete: open the link from your invitation.',
|
|
18
|
+
newPassword: 'Password',
|
|
19
|
+
repeatPassword: 'Repeat the password',
|
|
20
|
+
passwordRule: 'At least 12 characters.',
|
|
21
|
+
mismatch: 'The passwords are not the same.',
|
|
22
|
+
activate: 'Save and sign in',
|
|
15
23
|
signIn: 'Sign in',
|
|
16
24
|
login: 'Login',
|
|
17
25
|
password: 'Password',
|
|
@@ -21,11 +29,32 @@ export const en = {
|
|
|
21
29
|
signOut: 'Sign out',
|
|
22
30
|
invalid: 'The login or password is wrong.',
|
|
23
31
|
adminNeeds2fa: 'Administrator rights apply after you verify a second factor.',
|
|
32
|
+
setupTitle: 'Set up two-factor sign-in',
|
|
33
|
+
setupIntro: 'This company requires a second step when you sign in: a code from an authenticator app on your phone. Set it up to continue.',
|
|
34
|
+
setupStart: 'Set it up',
|
|
35
|
+
setupStep1: 'Add this account to your authenticator app.',
|
|
36
|
+
setupOpenApp: 'Open in the app',
|
|
37
|
+
setupStep2: 'Or type this key:',
|
|
38
|
+
setupStep3: 'Enter the 6-digit code it shows.',
|
|
39
|
+
setupTurnOn: 'Turn on and continue',
|
|
40
|
+
setupCodes: 'Keep these recovery codes somewhere safe: each signs you in once if you lose your phone.',
|
|
41
|
+
setupContinue: 'Continue',
|
|
24
42
|
},
|
|
25
43
|
shell: {
|
|
26
44
|
apps: 'Apps',
|
|
27
45
|
menu: 'Main menu',
|
|
28
46
|
theme: 'Theme',
|
|
47
|
+
density: 'Density',
|
|
48
|
+
home: 'Home',
|
|
49
|
+
appNamed: '{{app}} app',
|
|
50
|
+
switchCompany: 'Company: {{name}} (switch)',
|
|
51
|
+
sidebar: 'Sidebar',
|
|
52
|
+
collapseSidebar: 'Collapse the sidebar',
|
|
53
|
+
expandSidebar: 'Expand the sidebar',
|
|
54
|
+
openMenu: 'Open the menu',
|
|
55
|
+
closeMenu: 'Close the menu',
|
|
56
|
+
menuHint: 'Apps and their sections',
|
|
57
|
+
location: 'You are here',
|
|
29
58
|
light: 'Light',
|
|
30
59
|
dark: 'Dark',
|
|
31
60
|
system: 'System',
|
|
@@ -62,11 +91,26 @@ export const en = {
|
|
|
62
91
|
exportFailed: 'The export failed: {{reason}}',
|
|
63
92
|
columns: 'Columns',
|
|
64
93
|
density: 'Density',
|
|
94
|
+
statusOf: '{{field}}: {{state}}',
|
|
95
|
+
nextState: 'Next',
|
|
96
|
+
recordActions: 'Record actions',
|
|
97
|
+
summary: 'Summary',
|
|
98
|
+
details: 'Details',
|
|
99
|
+
recordPanel: 'About this record',
|
|
100
|
+
showPanel: 'Show the panel',
|
|
101
|
+
hidePanel: 'Hide the panel',
|
|
102
|
+
previousMonth: 'Previous month',
|
|
103
|
+
nextMonth: 'Next month',
|
|
104
|
+
pickDate: 'Pick a date',
|
|
105
|
+
datePlaceholder: 'Date',
|
|
106
|
+
today: 'Today',
|
|
107
|
+
clear: 'Clear',
|
|
65
108
|
proposed: 'Proposed',
|
|
66
109
|
design: { addField: 'Add field', addColumn: 'Add column' },
|
|
67
110
|
compact: 'Compact',
|
|
68
111
|
comfortable: 'Comfortable',
|
|
69
112
|
emptyTitle: 'Nothing here yet',
|
|
113
|
+
emptyNamed: 'No {{name}} yet',
|
|
70
114
|
emptyHint: 'Records matching the current search will appear here.',
|
|
71
115
|
emptyFiltered: 'No record matches the current search.',
|
|
72
116
|
moved: '{{name}} moved to {{column}}',
|
|
@@ -188,9 +232,35 @@ export const en = {
|
|
|
188
232
|
done: 'Mark done',
|
|
189
233
|
recent: 'Recently opened',
|
|
190
234
|
apps: 'Apps',
|
|
235
|
+
today: 'Today, {{date}}',
|
|
236
|
+
approve: 'Approve {{record}}',
|
|
237
|
+
review: 'Review',
|
|
238
|
+
dueToday: 'due today',
|
|
239
|
+
mentioned: '{{actor}} mentioned you on {{record}}',
|
|
240
|
+
saved: 'Your saved views',
|
|
191
241
|
},
|
|
192
242
|
toast: { region: 'Notifications', close: 'Close' },
|
|
243
|
+
image: {
|
|
244
|
+
choosePhoto: 'Change photo',
|
|
245
|
+
chooseLogo: 'Change logo',
|
|
246
|
+
remove: 'Remove',
|
|
247
|
+
hint: 'PNG, JPEG or WebP. It is made small (256 px) before it is sent.',
|
|
248
|
+
unreadable: 'This file is not an image the browser can read.',
|
|
249
|
+
},
|
|
250
|
+
oauth: {
|
|
251
|
+
title: '{{app}} wants to use your account',
|
|
252
|
+
as: 'Signed in as {{name}} ({{login}}).',
|
|
253
|
+
may: 'It will be able to:',
|
|
254
|
+
limits: 'Never more than you may do yourself. You can take this back at any time in Connected apps.',
|
|
255
|
+
back: 'You will go back to {{host}}.',
|
|
256
|
+
homepage: 'About the app',
|
|
257
|
+
already: 'You allowed this before.',
|
|
258
|
+
allow: 'Allow',
|
|
259
|
+
cancel: 'Cancel',
|
|
260
|
+
},
|
|
193
261
|
palette: {
|
|
262
|
+
switchCompany: 'Switch to {{name}}',
|
|
263
|
+
profile: 'Your profile',
|
|
194
264
|
button: 'Search or jump to…',
|
|
195
265
|
title: 'Command palette',
|
|
196
266
|
description: 'Search records, menus and commands. Use the arrow keys and Enter.',
|
|
@@ -209,6 +279,7 @@ export const en = {
|
|
|
209
279
|
shortcuts: {
|
|
210
280
|
title: 'Keyboard shortcuts',
|
|
211
281
|
palette: 'Search or jump anywhere',
|
|
282
|
+
sidebar: 'Collapse or expand the sidebar',
|
|
212
283
|
search: 'Focus the search box',
|
|
213
284
|
new: 'New record',
|
|
214
285
|
views: 'Switch view',
|
|
@@ -235,6 +306,11 @@ export const en = {
|
|
|
235
306
|
custom: 'Custom filter',
|
|
236
307
|
remove: 'Remove {{facet}}',
|
|
237
308
|
or: 'or',
|
|
309
|
+
savedViews: 'Saved views',
|
|
310
|
+
allRecords: 'All',
|
|
311
|
+
moreViews_one: '{{count}} more',
|
|
312
|
+
moreViews_other: '{{count}} more',
|
|
313
|
+
shared: 'Shared',
|
|
238
314
|
},
|
|
239
315
|
};
|
|
240
316
|
export const bn = {
|
|
@@ -247,6 +323,14 @@ export const bn = {
|
|
|
247
323
|
unknownPage: '"{{page}}" পৃষ্ঠাটি এই অ্যাপে নেই। registry.registerPage দিয়ে নিবন্ধন করুন।',
|
|
248
324
|
},
|
|
249
325
|
auth: {
|
|
326
|
+
activateTitle: 'আপনার পাসওয়ার্ড বেছে নিন',
|
|
327
|
+
activateIntro: 'আপনাকে Shutro ERP-এ আমন্ত্রণ জানানো হয়েছে। শুরু করতে একটি পাসওয়ার্ড বেছে নিন।',
|
|
328
|
+
activateNoToken: 'লিংকটি অসম্পূর্ণ: আমন্ত্রণের লিংকটি খুলুন।',
|
|
329
|
+
newPassword: 'পাসওয়ার্ড',
|
|
330
|
+
repeatPassword: 'পাসওয়ার্ড আবার লিখুন',
|
|
331
|
+
passwordRule: 'কমপক্ষে ১২ অক্ষর।',
|
|
332
|
+
mismatch: 'পাসওয়ার্ড দুটি মেলেনি।',
|
|
333
|
+
activate: 'সংরক্ষণ করে সাইন ইন করুন',
|
|
250
334
|
signIn: 'সাইন ইন',
|
|
251
335
|
login: 'লগইন',
|
|
252
336
|
password: 'পাসওয়ার্ড',
|
|
@@ -256,11 +340,32 @@ export const bn = {
|
|
|
256
340
|
signOut: 'সাইন আউট',
|
|
257
341
|
invalid: 'লগইন বা পাসওয়ার্ড ভুল।',
|
|
258
342
|
adminNeeds2fa: 'দ্বিতীয় ধাপ যাচাইয়ের পর অ্যাডমিনিস্ট্রেটরের অধিকার কার্যকর হবে।',
|
|
343
|
+
setupTitle: 'দুই-ধাপের সাইন-ইন চালু করুন',
|
|
344
|
+
setupIntro: 'এই প্রতিষ্ঠানে সাইন-ইনের সময় একটি দ্বিতীয় ধাপ লাগে: ফোনের অথেনটিকেটর অ্যাপের একটি কোড। চালিয়ে যেতে এটি চালু করুন।',
|
|
345
|
+
setupStart: 'চালু করুন',
|
|
346
|
+
setupStep1: 'অ্যাকাউন্টটি আপনার অথেনটিকেটর অ্যাপে যোগ করুন।',
|
|
347
|
+
setupOpenApp: 'অ্যাপে খুলুন',
|
|
348
|
+
setupStep2: 'অথবা এই কী লিখুন:',
|
|
349
|
+
setupStep3: 'অ্যাপে দেখানো ৬-সংখ্যার কোড দিন।',
|
|
350
|
+
setupTurnOn: 'চালু করে এগিয়ে যান',
|
|
351
|
+
setupCodes: 'এই রিকভারি কোডগুলো নিরাপদে রাখুন: ফোন হারালে প্রতিটি একবার সাইন-ইন করায়।',
|
|
352
|
+
setupContinue: 'এগিয়ে যান',
|
|
259
353
|
},
|
|
260
354
|
shell: {
|
|
261
355
|
apps: 'অ্যাপস',
|
|
262
356
|
menu: 'প্রধান মেনু',
|
|
263
357
|
theme: 'থিম',
|
|
358
|
+
density: 'ঘনত্ব',
|
|
359
|
+
home: 'হোম',
|
|
360
|
+
appNamed: '{{app}} অ্যাপ',
|
|
361
|
+
switchCompany: 'প্রতিষ্ঠান: {{name}} (বদলান)',
|
|
362
|
+
sidebar: 'সাইডবার',
|
|
363
|
+
collapseSidebar: 'সাইডবার ছোট করুন',
|
|
364
|
+
expandSidebar: 'সাইডবার বড় করুন',
|
|
365
|
+
openMenu: 'মেনু খুলুন',
|
|
366
|
+
closeMenu: 'মেনু বন্ধ করুন',
|
|
367
|
+
menuHint: 'অ্যাপ ও তাদের অংশ',
|
|
368
|
+
location: 'আপনি এখানে আছেন',
|
|
264
369
|
light: 'লাইট',
|
|
265
370
|
dark: 'ডার্ক',
|
|
266
371
|
system: 'সিস্টেম',
|
|
@@ -297,11 +402,26 @@ export const bn = {
|
|
|
297
402
|
exportFailed: 'এক্সপোর্ট ব্যর্থ: {{reason}}',
|
|
298
403
|
columns: 'কলাম',
|
|
299
404
|
density: 'ঘনত্ব',
|
|
405
|
+
statusOf: '{{field}}: {{state}}',
|
|
406
|
+
nextState: 'পরবর্তী',
|
|
407
|
+
recordActions: 'রেকর্ডের কাজ',
|
|
408
|
+
summary: 'সারাংশ',
|
|
409
|
+
details: 'বিস্তারিত',
|
|
410
|
+
recordPanel: 'এই রেকর্ড সম্পর্কে',
|
|
411
|
+
showPanel: 'প্যানেল দেখান',
|
|
412
|
+
hidePanel: 'প্যানেল লুকান',
|
|
413
|
+
previousMonth: 'আগের মাস',
|
|
414
|
+
nextMonth: 'পরের মাস',
|
|
415
|
+
pickDate: 'তারিখ বাছুন',
|
|
416
|
+
datePlaceholder: 'তারিখ',
|
|
417
|
+
today: 'আজ',
|
|
418
|
+
clear: 'মুছে ফেলুন',
|
|
300
419
|
proposed: 'প্রস্তাবিত',
|
|
301
420
|
design: { addField: 'ফিল্ড যোগ করুন', addColumn: 'কলাম যোগ করুন' },
|
|
302
421
|
compact: 'সংক্ষিপ্ত',
|
|
303
422
|
comfortable: 'স্বাভাবিক',
|
|
304
423
|
emptyTitle: 'এখানে এখনো কিছু নেই',
|
|
424
|
+
emptyNamed: 'এখনো কোনো {{name}} নেই',
|
|
305
425
|
emptyHint: 'বর্তমান খোঁজের সাথে মেলা রেকর্ড এখানে দেখা যাবে।',
|
|
306
426
|
emptyFiltered: 'বর্তমান খোঁজের সাথে কোনো রেকর্ড মেলেনি।',
|
|
307
427
|
moved: '{{name}} {{column}}-এ সরানো হয়েছে',
|
|
@@ -420,9 +540,35 @@ export const bn = {
|
|
|
420
540
|
done: 'সম্পন্ন',
|
|
421
541
|
recent: 'সম্প্রতি খোলা',
|
|
422
542
|
apps: 'অ্যাপস',
|
|
543
|
+
today: 'আজ, {{date}}',
|
|
544
|
+
approve: '{{record}} অনুমোদন করুন',
|
|
545
|
+
review: 'দেখুন',
|
|
546
|
+
dueToday: 'আজকের',
|
|
547
|
+
mentioned: '{{actor}} আপনাকে {{record}}-এ উল্লেখ করেছেন',
|
|
548
|
+
saved: 'আপনার সংরক্ষিত ভিউ',
|
|
423
549
|
},
|
|
424
550
|
toast: { region: 'বিজ্ঞপ্তি', close: 'বন্ধ করুন' },
|
|
551
|
+
image: {
|
|
552
|
+
choosePhoto: 'ছবি বদলান',
|
|
553
|
+
chooseLogo: 'লোগো বদলান',
|
|
554
|
+
remove: 'সরান',
|
|
555
|
+
hint: 'PNG, JPEG বা WebP। পাঠানোর আগে ছোট (২৫৬ px) করা হয়।',
|
|
556
|
+
unreadable: 'এই ফাইলটি ব্রাউজার পড়তে পারে এমন ছবি নয়।',
|
|
557
|
+
},
|
|
558
|
+
oauth: {
|
|
559
|
+
title: '{{app}} আপনার অ্যাকাউন্ট ব্যবহার করতে চায়',
|
|
560
|
+
as: '{{name}} ({{login}}) হিসেবে সাইন ইন করা।',
|
|
561
|
+
may: 'এটি যা করতে পারবে:',
|
|
562
|
+
limits: 'আপনি নিজে যা পারেন তার বেশি কখনো নয়। যেকোনো সময় সংযুক্ত অ্যাপস থেকে ফিরিয়ে নিতে পারেন।',
|
|
563
|
+
back: 'আপনি {{host}}-এ ফিরে যাবেন।',
|
|
564
|
+
homepage: 'অ্যাপ সম্পর্কে',
|
|
565
|
+
already: 'আপনি আগে এটি অনুমতি দিয়েছিলেন।',
|
|
566
|
+
allow: 'অনুমতি দিন',
|
|
567
|
+
cancel: 'বাতিল',
|
|
568
|
+
},
|
|
425
569
|
palette: {
|
|
570
|
+
switchCompany: '{{name}}-এ যান',
|
|
571
|
+
profile: 'আপনার প্রোফাইল',
|
|
426
572
|
button: 'খুঁজুন বা যান…',
|
|
427
573
|
title: 'কমান্ড প্যালেট',
|
|
428
574
|
description: 'রেকর্ড, মেনু ও কমান্ড খুঁজুন। তীর কী ও এন্টার ব্যবহার করুন।',
|
|
@@ -441,6 +587,7 @@ export const bn = {
|
|
|
441
587
|
shortcuts: {
|
|
442
588
|
title: 'কীবোর্ড শর্টকাট',
|
|
443
589
|
palette: 'যেকোনো জায়গায় খুঁজুন বা যান',
|
|
590
|
+
sidebar: 'সাইডবার ছোট বা বড় করুন',
|
|
444
591
|
search: 'সার্চ বক্সে যান',
|
|
445
592
|
new: 'নতুন রেকর্ড',
|
|
446
593
|
views: 'ভিউ বদলান',
|
|
@@ -467,6 +614,11 @@ export const bn = {
|
|
|
467
614
|
custom: 'নিজস্ব ফিল্টার',
|
|
468
615
|
remove: '{{facet}} সরান',
|
|
469
616
|
or: 'অথবা',
|
|
617
|
+
savedViews: 'সংরক্ষিত ভিউ',
|
|
618
|
+
allRecords: 'সব',
|
|
619
|
+
moreViews_one: 'আরও {{count}}টি',
|
|
620
|
+
moreViews_other: 'আরও {{count}}টি',
|
|
621
|
+
shared: 'শেয়ার করা',
|
|
470
622
|
},
|
|
471
623
|
};
|
|
472
624
|
export const ar = {
|
package/dist/ui/index.d.ts
CHANGED
|
@@ -8,13 +8,15 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { Registry } from './registry.js';
|
|
10
10
|
export { ApiError, type ApiOptions, type AppEntry, type CurrentUser, createKoshApi, type KoshApi, type ListQuery, type MenuNode, NetworkError, type Problem, type Row, type ServedView, type Versioned, type ViewField, } from './api.js';
|
|
11
|
-
export { KoshApp, type KoshAppProps } from './app.js';
|
|
11
|
+
export { KoshApp, type KoshAppProps, useLanguage } from './app.js';
|
|
12
12
|
export { AppIcon } from './components/AppIcon.js';
|
|
13
|
+
export * from './components/Avatar.js';
|
|
13
14
|
export * from './components/primitives.js';
|
|
14
15
|
export { type KoshContextValue, KoshProvider, type ThemeChoice, useKosh, useTheme, } from './context.js';
|
|
15
16
|
export { type DesignContextValue, DesignProvider, type DesignSpot, useDesign, } from './design.js';
|
|
16
17
|
export { addMessages, createI18n, directionOf, NAMESPACE } from './i18n/index.js';
|
|
17
18
|
export { LANGUAGES } from './i18n/messages.js';
|
|
19
|
+
export { accentVariables, hexToOklch } from './lib/accent.js';
|
|
18
20
|
export { cn } from './lib/cn.js';
|
|
19
21
|
export { bcp47, createFormatter, type Formatter } from './lib/format.js';
|
|
20
22
|
export { type LiveRecord, useLiveModel, useLiveRecord } from './live.js';
|
package/dist/ui/index.js
CHANGED
|
@@ -12,13 +12,15 @@ import { KanbanView } from './views/KanbanView.js';
|
|
|
12
12
|
import { ListView } from './views/ListView.js';
|
|
13
13
|
import { registerDefaultWidgets } from './views/widgets.js';
|
|
14
14
|
export { ApiError, createKoshApi, NetworkError, } from './api.js';
|
|
15
|
-
export { KoshApp } from './app.js';
|
|
15
|
+
export { KoshApp, useLanguage } from './app.js';
|
|
16
16
|
export { AppIcon } from './components/AppIcon.js';
|
|
17
|
+
export * from './components/Avatar.js';
|
|
17
18
|
export * from './components/primitives.js';
|
|
18
19
|
export { KoshProvider, useKosh, useTheme, } from './context.js';
|
|
19
20
|
export { DesignProvider, useDesign, } from './design.js';
|
|
20
21
|
export { addMessages, createI18n, directionOf, NAMESPACE } from './i18n/index.js';
|
|
21
22
|
export { LANGUAGES } from './i18n/messages.js';
|
|
23
|
+
export { accentVariables, hexToOklch } from './lib/accent.js';
|
|
22
24
|
export { cn } from './lib/cn.js';
|
|
23
25
|
export { bcp47, createFormatter } from './lib/format.js';
|
|
24
26
|
export { useLiveModel, useLiveRecord } from './live.js';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A company's brand colour as the back-office's accent (RFC 0018 §4.5). Only its hue and chroma are used: the
|
|
3
|
+
* themes fix the accent's lightness (light: dark enough for white text; dark: light enough for dark text), so any
|
|
4
|
+
* brand colour keeps text on buttons and links readable (WCAG AA) in both.
|
|
5
|
+
*/
|
|
6
|
+
/** OKLCH of an sRGB hex colour (`#4f46e5` → `{ l, c, h }`), or null when it is not one. */
|
|
7
|
+
export declare function hexToOklch(hex: string): {
|
|
8
|
+
l: number;
|
|
9
|
+
c: number;
|
|
10
|
+
h: number;
|
|
11
|
+
} | null;
|
|
12
|
+
/** The CSS variables a brand colour sets (`--accent-h`, `--accent-c`), or none for the default accent. */
|
|
13
|
+
export declare function accentVariables(hex: string | null | undefined): Record<string, string>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A company's brand colour as the back-office's accent (RFC 0018 §4.5). Only its hue and chroma are used: the
|
|
3
|
+
* themes fix the accent's lightness (light: dark enough for white text; dark: light enough for dark text), so any
|
|
4
|
+
* brand colour keeps text on buttons and links readable (WCAG AA) in both.
|
|
5
|
+
*/
|
|
6
|
+
/** OKLCH of an sRGB hex colour (`#4f46e5` → `{ l, c, h }`), or null when it is not one. */
|
|
7
|
+
export function hexToOklch(hex) {
|
|
8
|
+
const m = /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(hex);
|
|
9
|
+
if (m === null)
|
|
10
|
+
return null;
|
|
11
|
+
const linear = (v) => {
|
|
12
|
+
const x = Number.parseInt(v, 16) / 255;
|
|
13
|
+
return x <= 0.04045 ? x / 12.92 : ((x + 0.055) / 1.055) ** 2.4;
|
|
14
|
+
};
|
|
15
|
+
const [r, g, b] = [linear(m[1]), linear(m[2]), linear(m[3])];
|
|
16
|
+
const l_ = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);
|
|
17
|
+
const m_ = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);
|
|
18
|
+
const s_ = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);
|
|
19
|
+
const L = 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_;
|
|
20
|
+
const A = 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_;
|
|
21
|
+
const B = 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_;
|
|
22
|
+
const c = Math.sqrt(A * A + B * B);
|
|
23
|
+
const h = (Math.atan2(B, A) * 180) / Math.PI;
|
|
24
|
+
return { l: L, c, h: h < 0 ? h + 360 : h };
|
|
25
|
+
}
|
|
26
|
+
/** The CSS variables a brand colour sets (`--accent-h`, `--accent-c`), or none for the default accent. */
|
|
27
|
+
export function accentVariables(hex) {
|
|
28
|
+
const color = hex === null || hex === undefined ? null : hexToOklch(hex);
|
|
29
|
+
if (color === null)
|
|
30
|
+
return {};
|
|
31
|
+
// Chroma is capped (very saturated colours glare as large surfaces); greys stay grey.
|
|
32
|
+
return {
|
|
33
|
+
'--accent-h': color.h.toFixed(1),
|
|
34
|
+
'--accent-c': Math.min(color.c, 0.2).toFixed(3),
|
|
35
|
+
};
|
|
36
|
+
}
|
package/dist/ui/registry.d.ts
CHANGED
|
@@ -124,9 +124,13 @@ export declare class Registry {
|
|
|
124
124
|
/** The widget for a node: its `widget`, else the field kind, else plain text. */
|
|
125
125
|
widget(node: FieldNode, field: ViewField): ComponentType<WidgetProps>;
|
|
126
126
|
component(name: string): ComponentType<NodeComponentProps> | undefined;
|
|
127
|
-
/**
|
|
127
|
+
/**
|
|
128
|
+
* An item of the shell's header, before the language and theme menus (`notify.Bell`). With `home`, it is also in
|
|
129
|
+
* the home page's corner, next to the account menu (notifications, messages).
|
|
130
|
+
*/
|
|
128
131
|
registerHeaderItem(name: string, component: ComponentType<HeaderItemProps>, options?: {
|
|
129
132
|
readonly replace?: boolean;
|
|
133
|
+
readonly home?: boolean;
|
|
130
134
|
}): this;
|
|
131
135
|
/**
|
|
132
136
|
* A personal page every signed-in user reaches from the user menu, outside any app (`settings.ApiKeys`):
|
|
@@ -147,6 +151,8 @@ export declare class Registry {
|
|
|
147
151
|
headerItems(): readonly {
|
|
148
152
|
readonly name: string;
|
|
149
153
|
readonly component: ComponentType<HeaderItemProps>;
|
|
154
|
+
/** Also on the home page. */
|
|
155
|
+
readonly home: boolean;
|
|
150
156
|
}[];
|
|
151
157
|
/** A control next to every search box (the AI assistant's "Ask"). */
|
|
152
158
|
registerSearchAssist(name: string, component: ComponentType<SearchAssistProps>, options?: {
|
package/dist/ui/registry.js
CHANGED
|
@@ -55,8 +55,16 @@ export class Registry {
|
|
|
55
55
|
component(name) {
|
|
56
56
|
return this.#entries.component.get(name);
|
|
57
57
|
}
|
|
58
|
-
|
|
58
|
+
#homeItems = new Set();
|
|
59
|
+
/**
|
|
60
|
+
* An item of the shell's header, before the language and theme menus (`notify.Bell`). With `home`, it is also in
|
|
61
|
+
* the home page's corner, next to the account menu (notifications, messages).
|
|
62
|
+
*/
|
|
59
63
|
registerHeaderItem(name, component, options = {}) {
|
|
64
|
+
if (options.home === true)
|
|
65
|
+
this.#homeItems.add(name);
|
|
66
|
+
else
|
|
67
|
+
this.#homeItems.delete(name);
|
|
60
68
|
return this.#add('header', name, component, options.replace === true);
|
|
61
69
|
}
|
|
62
70
|
#userPageLabels = new Map();
|
|
@@ -83,6 +91,7 @@ export class Registry {
|
|
|
83
91
|
return [...this.#entries.header].map(([name, component]) => ({
|
|
84
92
|
name,
|
|
85
93
|
component: component,
|
|
94
|
+
home: this.#homeItems.has(name),
|
|
86
95
|
}));
|
|
87
96
|
}
|
|
88
97
|
/** A control next to every search box (the AI assistant's "Ask"). */
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Saved views as tabs (RFC 0018 §4.3): above the search, *All* and the saved searches of this model and view type —
|
|
3
|
+
* the user's own and the shared ones —, the one matching the current search marked. A tab applies its search; more
|
|
4
|
+
* than a handful go into a *More* menu. Saving and the full list stay in the search bar's favorites menu; with
|
|
5
|
+
* nothing saved, there are no tabs.
|
|
6
|
+
*/
|
|
7
|
+
import { type SearchState } from '../../search/index.js';
|
|
8
|
+
import type { ReactElement } from 'react';
|
|
9
|
+
export declare function ViewTabs({ model, viewType, state, onChange, }: {
|
|
10
|
+
readonly model: string;
|
|
11
|
+
readonly viewType: string;
|
|
12
|
+
readonly state: SearchState;
|
|
13
|
+
readonly onChange: (state: SearchState) => void;
|
|
14
|
+
}): ReactElement | null;
|