arrmatura 5.0.4 → 5.2.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/commons/auth/AuthService.ts +111 -0
- package/commons/auth/UserService.ts +28 -78
- package/commons/auth/index.ts +4 -3
- package/commons/auth/user.xml +18 -20
- package/commons/components/buttons.xml +6 -4
- package/commons/components/layouts.xml +8 -8
- package/commons/components/modal.xml +4 -4
- package/commons/components/navigation.xml +21 -7
- package/commons/components/searchbar.xml +36 -22
- package/commons/components/table.xml +25 -5
- package/commons/components/toasts.xml +10 -5
- package/commons/forms/FormController.ts +48 -34
- package/commons/forms/Item.ts +93 -29
- package/commons/forms/ItemCollectionController.ts +113 -0
- package/commons/forms/ItemController.ts +50 -21
- package/commons/forms/NewItemController.ts +46 -0
- package/commons/forms/SmartareaField.xml +3 -3
- package/commons/forms/SuggestionField.xml +3 -3
- package/commons/forms/fields.xml +28 -15
- package/commons/forms/form.xml +3 -3
- package/commons/forms/index.ts +4 -4
- package/commons/index.ts +2 -2
- package/commons/services/ApiClientService.ts +32 -0
- package/commons/services/GSheetsService.ts +92 -64
- package/commons/services/Invoke.ts +24 -8
- package/commons/services/JsonpService.ts +1 -1
- package/commons/services/MetadataService.ts +50 -0
- package/commons/services/NavigationService.ts +20 -1
- package/commons/services/Service.ts +22 -28
- package/commons/services/Storage.ts +55 -0
- package/commons/services/ToastService.ts +16 -4
- package/commons/services/index.ts +3 -4
- package/core/Arrmatura.ts +4 -9
- package/core/CNode.ts +1 -2
- package/core/Component.ts +29 -31
- package/core/cnodes/conditionals.ts +3 -2
- package/core/expression.ts +1 -1
- package/core/register.ts +1 -1
- package/core/utils.ts +1 -3
- package/core-web/attributes.ts +38 -10
- package/core-web/elements.ts +22 -4
- package/core-web/index.ts +14 -2
- package/core-web/reflow.ts +3 -1
- package/core-web/support.ts +27 -0
- package/docs/index.js +350 -66
- package/lib/{arrayGroupBy.ts → array/arrayGroupBy.ts} +1 -1
- package/lib/{arraySortBy.ts → array/arraySortBy.ts} +5 -5
- package/lib/{arrayToObject.ts → array/arrayToObject.ts} +0 -0
- package/lib/array/arrayish.ts +7 -0
- package/lib/array/index.ts +4 -0
- package/lib/crypto/index.ts +25 -0
- package/lib/{dateFormat.ts → date/index.ts} +61 -3
- package/lib/func/curry.ts +11 -0
- package/lib/{fx.ts → func/fx.ts} +32 -38
- package/lib/{noop.ts → func/identity.ts} +1 -3
- package/lib/{nextId.ts → func/nextId.ts} +0 -0
- package/lib/func/noop.ts +6 -0
- package/lib/geo/index.js +22 -0
- package/lib/index.ts +17 -19
- package/lib/{obj.ts → object/index.ts} +8 -3
- package/lib/{codus.ts → parsing/codus.ts} +1 -1
- package/lib/{predicat.ts → parsing/compiler.ts} +0 -0
- package/lib/{scalar.ts → parsing/scalarParse.ts} +0 -0
- package/lib/{urls.ts → parsing/urls.ts} +0 -0
- package/lib/{xml.ts → parsing/xml.ts} +3 -3
- package/lib/{l10n.ts → resources/l10n.ts} +2 -2
- package/lib/{resources.ru.ts → resources/resources.ru.ts} +0 -0
- package/lib/{resources.ts → resources/resources.ts} +0 -0
- package/lib/{str.ts → string/index.ts} +2 -20
- package/lib/{createListeners.ts → support/createListeners.ts} +0 -0
- package/package.json +7 -6
- package/commons/forms/ItemCollection.ts +0 -152
- package/commons/forms/MetadataService.ts +0 -45
- package/commons/pipes/index.ts +0 -21
- package/commons/pipes/showCounts.ts +0 -16
- package/commons/services/LocalStorage.ts +0 -46
- package/lib/consts.ts +0 -3
- package/lib/curry.ts +0 -8
- package/lib/dateOf.ts +0 -31
- package/lib/dateParseISO8601.ts +0 -27
- package/lib/guid.ts +0 -7
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { Service } from '../services/Service';
|
|
2
|
+
import { Storage } from '../services/Storage';
|
|
3
|
+
|
|
4
|
+
export class AuthService extends Service {
|
|
5
|
+
authUrl: string = '';
|
|
6
|
+
local?: Storage;
|
|
7
|
+
initialToken: any;
|
|
8
|
+
$info: unknown;
|
|
9
|
+
afterSignedOut?: Procedure;
|
|
10
|
+
persistence: 'local' | 'session' | 'transient' = 'transient';
|
|
11
|
+
|
|
12
|
+
init() {
|
|
13
|
+
this.local = new Storage(this.persistence);
|
|
14
|
+
|
|
15
|
+
return !this.initialToken
|
|
16
|
+
? null
|
|
17
|
+
: {
|
|
18
|
+
token: this.initialToken,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
get token() {
|
|
23
|
+
return this.initialToken || this.local?.get('$auth_token');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
set token(token: string | null) {
|
|
27
|
+
this.local?.set('$auth_token', token);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
get isSignedIn() {
|
|
31
|
+
return !!this.token;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
get canSignOut() {
|
|
35
|
+
return !this.initialToken;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
signOut() {
|
|
39
|
+
new Storage('local').clear();
|
|
40
|
+
new Storage('session').clear();
|
|
41
|
+
this.initialToken = null;
|
|
42
|
+
this.token = null;
|
|
43
|
+
window.location.reload();
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
signIn(creds: any) {
|
|
48
|
+
const { username, password } = creds || {};
|
|
49
|
+
return fetch(this.authUrl + '?action=signin', {
|
|
50
|
+
method: 'POST',
|
|
51
|
+
mode: 'cors',
|
|
52
|
+
redirect: 'follow',
|
|
53
|
+
body: JSON.stringify({ creds: username + ':' + password }),
|
|
54
|
+
})
|
|
55
|
+
.then((res) => res.json())
|
|
56
|
+
.then(({ error, ...rest }) => {
|
|
57
|
+
if (error) {
|
|
58
|
+
throw new Error('Invalid credentials');
|
|
59
|
+
}
|
|
60
|
+
return rest;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
signUp(data: any) {
|
|
65
|
+
return fetch(this.authUrl + '?action=signup', {
|
|
66
|
+
method: 'POST',
|
|
67
|
+
mode: 'cors',
|
|
68
|
+
redirect: 'follow',
|
|
69
|
+
body: JSON.stringify({ data }),
|
|
70
|
+
})
|
|
71
|
+
.then((res) => res.json())
|
|
72
|
+
.then(({ error, ...rest }) => {
|
|
73
|
+
if (error) {
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
76
|
+
return rest;
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
onInvalidateToken() {
|
|
81
|
+
return this.signOut();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
onSignIn(creds: Hash) {
|
|
85
|
+
return {
|
|
86
|
+
busy: true,
|
|
87
|
+
'*': this.signIn(creds)
|
|
88
|
+
.catch((error) => {
|
|
89
|
+
this.toast('error: ' + error.message);
|
|
90
|
+
return null;
|
|
91
|
+
})
|
|
92
|
+
.then((info) => ({ busy: false, ...info })),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
onSignUp(creds: Hash) {
|
|
96
|
+
return {
|
|
97
|
+
busy: true,
|
|
98
|
+
'*': this.signUp(creds)
|
|
99
|
+
.catch((error) => {
|
|
100
|
+
this.toast('error: ' + error.message);
|
|
101
|
+
return null;
|
|
102
|
+
})
|
|
103
|
+
.then((info) => ({ busy: false, ...info })),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
onSignOut() {
|
|
108
|
+
this.signOut();
|
|
109
|
+
this.afterSignedOut?.();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -1,96 +1,52 @@
|
|
|
1
1
|
import { Service } from '../services/Service';
|
|
2
|
-
import {
|
|
3
|
-
import { LocalStorage } from '../services/LocalStorage';
|
|
2
|
+
import { Storage } from '../services/Storage';
|
|
4
3
|
|
|
5
4
|
export class UserService extends Service {
|
|
6
5
|
url: string = '';
|
|
7
6
|
kind: string = '$user';
|
|
8
|
-
local
|
|
9
|
-
|
|
10
|
-
$info: unknown;
|
|
11
|
-
|
|
12
|
-
init() {
|
|
13
|
-
return this.syncUserInfo();
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
syncUserInfo() {
|
|
17
|
-
const token = this.token || this.local?.get('$token');
|
|
18
|
-
|
|
19
|
-
return !token
|
|
20
|
-
? null
|
|
21
|
-
: {
|
|
22
|
-
isLoading: true,
|
|
23
|
-
'*': fetch(urlAppendParams(this.url, { action: 'user', token }), { redirect: 'follow' })
|
|
24
|
-
.then((res) => res.json())
|
|
25
|
-
.then(({ info, error }) => {
|
|
26
|
-
if (error) throw error;
|
|
27
|
-
this.log('sync' + this.kind, info);
|
|
28
|
-
this.local?.set('$token', token);
|
|
29
|
-
return { info, isLoading: false };
|
|
30
|
-
})
|
|
31
|
-
.catch((err) => {
|
|
32
|
-
this.toast({ mode: 'error', message: 'Ошибка: ' + JSON.stringify(err?.message || err || 'unknown') });
|
|
33
|
-
return { info: null, isLoading: false };
|
|
34
|
-
}),
|
|
35
|
-
};
|
|
36
|
-
}
|
|
7
|
+
local?: Storage;
|
|
8
|
+
persistence: 'local' | 'session' | 'transient' = 'transient';
|
|
37
9
|
|
|
38
10
|
set info(info: unknown) {
|
|
39
|
-
this.$info = info;
|
|
40
11
|
this.local?.set(this.kind, info);
|
|
41
12
|
}
|
|
42
13
|
|
|
43
|
-
get info() {
|
|
44
|
-
|
|
45
|
-
return info;
|
|
14
|
+
get info(): Delta {
|
|
15
|
+
return this.local?.get(this.kind);
|
|
46
16
|
}
|
|
47
17
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
18
|
+
init() {
|
|
19
|
+
this.local = new Storage(this.persistence);
|
|
51
20
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const { since, items: items0 = [] } = this.local?.get(this.kind) || { since: 0, items: {} };
|
|
21
|
+
return this.sync();
|
|
22
|
+
}
|
|
55
23
|
|
|
56
|
-
|
|
24
|
+
submit(_data: any): Promise<any> {
|
|
25
|
+
throw new Error('Method not implemented.');
|
|
26
|
+
}
|
|
57
27
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
redirect: 'follow',
|
|
64
|
-
body: JSON.stringify({ action: 'upsert', delta }),
|
|
28
|
+
sync(delta?: Delta) {
|
|
29
|
+
const promise = this.submit({ path: `?action=user`, body: { delta } })
|
|
30
|
+
.then(({ user }) => {
|
|
31
|
+
this.log('sync ' + this.kind, user);
|
|
32
|
+
return { isLoading: false, info: user };
|
|
65
33
|
})
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
// const items = { ...items0, ...arrayToObject(items1) };
|
|
72
|
-
this.toast('Сохранено успешно');
|
|
34
|
+
.catch((error) => {
|
|
35
|
+
const message = error?.message || error || 'unknown';
|
|
36
|
+
this.toast({ id: message, mode: 'error', message: 'Ошибка: ' + message });
|
|
37
|
+
return { isLoading: false, error: message };
|
|
38
|
+
});
|
|
73
39
|
|
|
74
|
-
// this.local?.set(this.kind, { since: now, items });
|
|
75
|
-
return { busy: false }; //items,
|
|
76
|
-
})
|
|
77
|
-
.catch((err) => {
|
|
78
|
-
this.toast({ mode: 'error', message: 'Ошибка: update ' + JSON.stringify(err?.message || err || 'unknown') });
|
|
79
|
-
return { busy: false };
|
|
80
|
-
}),
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
onUpdate(data, { info }) {
|
|
85
40
|
return {
|
|
86
|
-
|
|
41
|
+
isLoading: true,
|
|
42
|
+
info: { ...this.info, ...delta },
|
|
43
|
+
error: null,
|
|
44
|
+
'*': promise,
|
|
87
45
|
};
|
|
88
46
|
}
|
|
89
47
|
|
|
90
|
-
|
|
91
|
-
return
|
|
92
|
-
info: { id: 1, name: 'Me' },
|
|
93
|
-
};
|
|
48
|
+
onSave(delta: Delta) {
|
|
49
|
+
return this.sync(delta);
|
|
94
50
|
}
|
|
95
51
|
|
|
96
52
|
onShowProfile(showProfile = false) {
|
|
@@ -98,10 +54,4 @@ export class UserService extends Service {
|
|
|
98
54
|
showProfile,
|
|
99
55
|
};
|
|
100
56
|
}
|
|
101
|
-
|
|
102
|
-
onLogout() {
|
|
103
|
-
return {
|
|
104
|
-
info: { id: 0, name: 'Me222' },
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
57
|
}
|
package/commons/auth/index.ts
CHANGED
package/commons/auth/user.xml
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
<component id="UserBar">
|
|
2
|
-
<div class="float-right">
|
|
3
|
-
<
|
|
2
|
+
<div class="float-right" style="width: 1.5rem;">
|
|
3
|
+
<NoUserPanel ui:if="<-auth.isSignedIn|not">
|
|
4
4
|
<ui:else>
|
|
5
|
-
<
|
|
5
|
+
<UserLoading ui:if="<-user.isLoading">
|
|
6
6
|
<ui:else>
|
|
7
|
-
<UserPanel ui:props="<-user.info" defaultImage="assets/
|
|
7
|
+
<UserPanel ui:props="<-user.info" defaultImage="assets/person1.png"/>
|
|
8
8
|
</ui:else>
|
|
9
|
-
</
|
|
9
|
+
</UserLoading>
|
|
10
10
|
</ui:else>
|
|
11
|
-
</
|
|
11
|
+
</NoUserPanel>
|
|
12
12
|
</div>
|
|
13
13
|
</component>
|
|
14
14
|
|
|
@@ -26,21 +26,19 @@
|
|
|
26
26
|
|
|
27
27
|
<component id="UserPanel">
|
|
28
28
|
<div class="tile tile-centered">
|
|
29
|
-
<div class="tile-icon">
|
|
30
|
-
<div class="example-tile-icon c-hand" click="-> user.showProfile|truthy">
|
|
31
|
-
<figure class="avatar">
|
|
32
|
-
<img src="{image|or:@defaultImage}" alt="{name}" />
|
|
33
|
-
</figure>
|
|
34
|
-
</div>
|
|
35
|
-
</div>
|
|
36
29
|
<div class="tile-action">
|
|
37
30
|
<div class="dropdown dropdown-right">
|
|
38
|
-
<a class="btn btn-link dropdown-toggle" tabindex="0">
|
|
39
|
-
<
|
|
31
|
+
<a class="btn btn-link dropdown-toggle p-0" tabindex="0">
|
|
32
|
+
<figure class="avatar">
|
|
33
|
+
<img src="{image|or:@defaultImage}" alt="{name}" />
|
|
34
|
+
</figure>
|
|
40
35
|
</a>
|
|
41
36
|
<ul class="menu">
|
|
42
37
|
<li class="menu-item">
|
|
43
|
-
<a click="-> user.
|
|
38
|
+
<a click="-> user.showProfile|truthy">Profile</a>
|
|
39
|
+
</li>
|
|
40
|
+
<li class="menu-item" ui:if="<- auth.canSignOut">
|
|
41
|
+
<a click="-> auth.signOut">Exit</a>
|
|
44
42
|
</li>
|
|
45
43
|
</ul>
|
|
46
44
|
</div>
|
|
@@ -51,13 +49,13 @@
|
|
|
51
49
|
<component id="NoUserPanel">
|
|
52
50
|
<div class="tile tile-centered">
|
|
53
51
|
<div class="tile-action">
|
|
52
|
+
<a class="btn btn-link dropdown-toggle" click="-> auth.signIn">
|
|
53
|
+
<Icon type="people"/>
|
|
54
|
+
</a>
|
|
54
55
|
<div class="dropdown dropdown-right">
|
|
55
|
-
<a class="btn btn-link dropdown-toggle" tabindex="0">
|
|
56
|
-
<i class="icon icon-more-vert"></i >
|
|
57
|
-
</a>
|
|
58
56
|
<ul class="menu">
|
|
59
57
|
<li class="menu-item">
|
|
60
|
-
<a
|
|
58
|
+
<a>▶️Vxod</a>
|
|
61
59
|
</li>
|
|
62
60
|
</ul>
|
|
63
61
|
</div>
|
|
@@ -8,16 +8,18 @@
|
|
|
8
8
|
{link|then:btn-link}
|
|
9
9
|
c-hand
|
|
10
10
|
" style="{style}" data={data} click="{action}">
|
|
11
|
-
<span ui:if="{busy}" class="mx-2">
|
|
11
|
+
<span ui:if="{busy}" class="mx-2" style="width:18px;">
|
|
12
12
|
<i class="loading"></i>
|
|
13
13
|
</span>
|
|
14
|
-
<Icon ui:if="
|
|
14
|
+
<Icon ui:if="busy|not|and:@icon" bundle="{iconBundle}" type="{icon}" class="mr-2"/>
|
|
15
15
|
<span ui:if="{title}" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis">{title}</span>
|
|
16
16
|
</button>
|
|
17
17
|
</component>
|
|
18
18
|
|
|
19
19
|
<component id="FAB">
|
|
20
|
-
<button class="btn {tooltip|then:tooltip} tooltip-left fixed
|
|
21
|
-
<
|
|
20
|
+
<button class="btn {tooltip|then:tooltip} tooltip-left p-0 fixed s-circle bg-error c-hand {class} {disabled|or:@busy|then:disabled} {busy|then:loading}" style="position: fixed; border: none; right: 1.5rem; bottom: 1.5rem; width: 2.5rem; height: 2.5rem;" data-tooltip="{tooltip|or:}">
|
|
21
|
+
<div class="centroid s-circle" style="width: 2.5rem; height: 2.5rem;" data="{data}" click="{action}">
|
|
22
|
+
<Icon type="{icon|or:plus}" />
|
|
23
|
+
</div>
|
|
22
24
|
</button>
|
|
23
25
|
</component>
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
<component id="Container">
|
|
2
|
-
<div class="container {class}" style="max-width: 720px;">
|
|
3
|
-
<a name="top"></a>
|
|
4
|
-
<ui:slot />
|
|
5
|
-
</div>
|
|
6
|
-
</component>
|
|
7
|
-
|
|
8
1
|
<component id="Panel">
|
|
9
2
|
<h6 class="mt-2 pt-2 px-2 text-gray" ui:if="caption">{caption}</h6>
|
|
10
3
|
<div class="panel {class}" style="{style}">
|
|
@@ -60,7 +53,7 @@
|
|
|
60
53
|
<div class="card-body">
|
|
61
54
|
<ui:slot />
|
|
62
55
|
</div>
|
|
63
|
-
<div class="card-footer">
|
|
56
|
+
<div class="card-footer" ui:if="slot(footer)">
|
|
64
57
|
<ui:slot id="footer" />
|
|
65
58
|
</div>
|
|
66
59
|
</div>
|
|
@@ -75,3 +68,10 @@
|
|
|
75
68
|
</component>
|
|
76
69
|
|
|
77
70
|
|
|
71
|
+
<component id="FixedPanel">
|
|
72
|
+
<div style="position: fixed; right: 0; {bottom|then:bottom:top}: 0; left: 0; z-index:3;">
|
|
73
|
+
<div class="{class}" style="max-width: 720px; margin: auto; display: flex; {style}">
|
|
74
|
+
<ui:slot />
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
</component>
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
- mode: lg|sm
|
|
16
16
|
|
|
17
17
|
-->
|
|
18
|
-
<div class="modal modal-{mode} {open|then:active}">
|
|
19
|
-
<a class="modal-overlay" aria-label="Close" click="{close}"></a>
|
|
18
|
+
<div class="modal modal-{mode} {open|then:active}" style="padding:0;">
|
|
19
|
+
<a class="modal-overlay" aria-label="Close" click="{close}" ui:if="mode|equals:lg|not"></a>
|
|
20
20
|
<div class="modal-container" style="padding:0;max-height: {mode|equals:lg|then:100:70}vh">
|
|
21
|
-
<div class="modal-header" style="
|
|
22
|
-
<a class="btn btn-clear float-right" aria-label=":close" click="{close}"></a>
|
|
21
|
+
<div class="modal-header bg-secondary" style="margin:0">
|
|
22
|
+
<a class="btn btn-lg btn-clear float-right" aria-label=":close" click="{close}"></a>
|
|
23
23
|
<div class="modal-title h5" ui:if="{title}">{title}</div>
|
|
24
24
|
<ui:slot id="header" />
|
|
25
25
|
</div>
|
|
@@ -16,16 +16,15 @@
|
|
|
16
16
|
</component>
|
|
17
17
|
|
|
18
18
|
<component id="Navbar">
|
|
19
|
-
<header class="navbar sticky {class} bg-secondary" style="
|
|
20
|
-
<section class="navbar-section">
|
|
21
|
-
<div class="m-2
|
|
19
|
+
<header class="navbar sticky {class} bg-secondary" style="height: 48px;flex-wrap: nowrap;margin:0;">
|
|
20
|
+
<section class="navbar-section" style="max-width:100%;">
|
|
21
|
+
<div class="m-2 d-flex items-center flex-1">
|
|
22
22
|
<ui:slot id="left" />
|
|
23
|
-
<
|
|
23
|
+
<div style="flex:1; min-height:1.7rem;display:flex;align-items: center;">
|
|
24
|
+
<h4 class="text-dark text-ellipsis {badge|then:badge}" style="margin-bottom:0; flex:1;max-width:640px;" data-badge="{badge}" ui:if="{caption}">{caption}</h4>
|
|
25
|
+
</div>
|
|
24
26
|
</div>
|
|
25
27
|
</section>
|
|
26
|
-
<section class="navbar-center" ui:if="{logo}">
|
|
27
|
-
<img src="{logo}" style="max-height: 44px" />
|
|
28
|
-
</section>
|
|
29
28
|
<section class="navbar-section flex-0 mx-2" ui:if="slot(right)">
|
|
30
29
|
<ui:slot id="right" />
|
|
31
30
|
</section>
|
|
@@ -57,3 +56,18 @@
|
|
|
57
56
|
<ui:slot />
|
|
58
57
|
</a>
|
|
59
58
|
</component>
|
|
59
|
+
|
|
60
|
+
<component id="NavListCursor">
|
|
61
|
+
<div class="d-flex {class}" style="min-width: 6rem;align-items: center;" ui:if="total">
|
|
62
|
+
<span class="p-2" ui:if="prev.id|not">
|
|
63
|
+
<Icon type="arrow-left"/>
|
|
64
|
+
</span>
|
|
65
|
+
<a class="p-2" href="#/task?itemId={prev.id}" ui:if="prev.id">
|
|
66
|
+
<Icon type="arrow-left"/>
|
|
67
|
+
</a>
|
|
68
|
+
<span class="text-dark text-ellipsis text-bold">{index|plus:1} / {total}</span>
|
|
69
|
+
<a class="p-2" href="#/task?itemId={next.id}" ui:if="next.id">
|
|
70
|
+
<Icon type="arrow-right"/>
|
|
71
|
+
</a>
|
|
72
|
+
</div>
|
|
73
|
+
</component>
|
|
@@ -8,33 +8,47 @@
|
|
|
8
8
|
</component>
|
|
9
9
|
|
|
10
10
|
<component id="SearchBarWithSuggestions">
|
|
11
|
-
<ui:fragment ui:if="opened.value">
|
|
12
|
-
<ui:then>
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
11
|
+
<!-- <ui:fragment ui:if="opened.value|or:@value">
|
|
12
|
+
<ui:then> -->
|
|
13
|
+
<div class="form-autocomplete mx-2">
|
|
14
|
+
<!-- autocomplete input container -->
|
|
15
|
+
<div class="form-autocomplete-input form-input input-sm">
|
|
16
|
+
<div class="input-group input-inline">
|
|
17
|
+
<input class="form-input" type="search" placeholder=":kluq_poshuku" keypress="{input}" value="{value}" focus="->opened|assignKeyValue:value:true" style="width:inherit" />
|
|
18
|
+
<i class="icon icon-cross m-2 c-hand" data-value="" click="{enter}" click2="->opened|assignKeyValue:value:false" ui:if="value"></i>
|
|
19
|
+
<i class="icon icon-search m-2 c-hand" click="->opened|assignKeyValue:value:false" ui:if="value|not"></i>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
<ui:fragment ui:if="opened.value|then:@suggestions">
|
|
23
|
+
<div style="position:fixed; right:0; top:0; left:0; bottom:0;" click="->opened|assignKeyValue:value:false"></div>
|
|
24
|
+
<ul class="menu" style="min-width: 140px;max-height:16rem;overflow-y:auto;">
|
|
25
|
+
<ui:fragment ui:if="suggestions.length">
|
|
26
|
+
<ui:then>
|
|
27
|
+
<li class="menu-item c-hand" ui:for="item of suggestions" data-value="{item.id}" click="{enter}">
|
|
28
|
+
<a>
|
|
29
|
+
<div class="tile tile-centered">
|
|
30
|
+
<div class="tile-content">{item.name}</div>
|
|
31
|
+
</div>
|
|
32
|
+
</a>
|
|
33
|
+
</li>
|
|
34
|
+
</ui:then>
|
|
35
|
+
<ui:else>
|
|
36
|
+
<li class="menu-item">
|
|
25
37
|
<div class="tile tile-centered">
|
|
26
|
-
<div class="tile-content"
|
|
38
|
+
<div class="tile-content text-gray">:strings.no_findings|or:no findings</div>
|
|
27
39
|
</div>
|
|
28
|
-
</
|
|
29
|
-
</
|
|
30
|
-
</
|
|
31
|
-
</
|
|
32
|
-
</ui:
|
|
40
|
+
</li>
|
|
41
|
+
</ui:else>
|
|
42
|
+
</ui:fragment>
|
|
43
|
+
</ul>
|
|
44
|
+
</ui:fragment>
|
|
45
|
+
</div>
|
|
46
|
+
<!-- </ui:then>
|
|
33
47
|
<ui:else>
|
|
34
|
-
<div class="mx-2" click="{open|
|
|
48
|
+
<div class="mx-2" click="{open|fnBindArgs:true}">
|
|
35
49
|
<i class="icon icon-search m-2 c-hand" click="->opened|assignKeyValue:value:true"></i>
|
|
36
50
|
</div>
|
|
37
51
|
</ui:else>
|
|
38
|
-
</ui:fragment>
|
|
52
|
+
</ui:fragment> -->
|
|
39
53
|
|
|
40
54
|
</component>
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
</component>
|
|
4
4
|
|
|
5
5
|
<component id="EmptyData">
|
|
6
|
-
<div class="empty w100 {class}">
|
|
6
|
+
<div class="empty w100 m-0 {class}">
|
|
7
7
|
<div class="empty-icon">
|
|
8
8
|
<Icon type="{icon|or:people}" />
|
|
9
9
|
</div>
|
|
@@ -15,6 +15,26 @@
|
|
|
15
15
|
</div>
|
|
16
16
|
</component>
|
|
17
17
|
|
|
18
|
+
<component id="AsyncLoader">
|
|
19
|
+
<ui:fragment ui:if="isLoading">
|
|
20
|
+
<ui:then>
|
|
21
|
+
<EmptyData class="h100" title="{title}" subtitle="{error|then::@subtitle}" icon="{icon|or:download}">
|
|
22
|
+
<ui:fragment ui:if="error|not">
|
|
23
|
+
<ui:then>
|
|
24
|
+
<LoadingIndicator/>
|
|
25
|
+
</ui:then>
|
|
26
|
+
<ui:else>
|
|
27
|
+
<Btn mode="error" action="{onError}" title="Error: {error}"/>
|
|
28
|
+
</ui:else>
|
|
29
|
+
</ui:fragment>
|
|
30
|
+
</EmptyData>
|
|
31
|
+
</ui:then>
|
|
32
|
+
<ui:else>
|
|
33
|
+
<ui:slot />
|
|
34
|
+
</ui:else>
|
|
35
|
+
</ui:fragment>
|
|
36
|
+
</component>
|
|
37
|
+
|
|
18
38
|
<component id="LoadableItems">
|
|
19
39
|
<LoadingIndicator class="empty" ui:if="data|not">
|
|
20
40
|
<ui:else>
|
|
@@ -105,14 +125,14 @@
|
|
|
105
125
|
</component>
|
|
106
126
|
|
|
107
127
|
<component id="Chips">
|
|
108
|
-
<div class="py-2
|
|
128
|
+
<div class="chips mx-0 py-2 px-2 {class}">
|
|
109
129
|
<div class="ui mini labels">
|
|
110
|
-
<span class="chip
|
|
130
|
+
<span class="chip {tag.selected|then:bg-success:bg-secondary} {tag.nonSelectable|then::c-hand} {tag.count|then:badge}" data-badge="{tag.count}" style="padding:1.2rem" data-id="{tag.id}" click="{tag.nonSelectable|then:undefined:@click}" ui:for="tag of data">
|
|
111
131
|
<span>
|
|
112
|
-
<
|
|
132
|
+
<b>{tag.name}</b>
|
|
113
133
|
</span>
|
|
114
134
|
</span>
|
|
115
|
-
<span ui:if="data|
|
|
135
|
+
<span ui:if="data|find:true:selected" class="label py-1 px-2 s-circle c-hand" click="{click|assignFirstArgKeyValue:id:}">
|
|
116
136
|
<Icon type="cross"/>
|
|
117
137
|
</span>
|
|
118
138
|
</div>
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
<component id="ToastList">
|
|
2
|
-
<div style="position:absolute;top:
|
|
3
|
-
<
|
|
2
|
+
<div style="position:absolute;top:2.5rem;right:1rem;left:1rem;z-index:500;{style}">
|
|
3
|
+
<div style="max-width: 600px;margin: auto;">
|
|
4
|
+
<Toast ui:props={toast} ui:for="toast of <-toasters.items"/>
|
|
5
|
+
</div>
|
|
4
6
|
</div>
|
|
5
7
|
</component>
|
|
6
8
|
|
|
7
9
|
<component id="Toast">
|
|
8
10
|
<div class="toast mt-1 toast-{mode|or:@mode|or:primary}">
|
|
9
11
|
<button class="btn btn-clear float-right" click="{close}"></button>
|
|
10
|
-
<p>
|
|
12
|
+
<p>
|
|
13
|
+
<b ui:if="counter" class="mr-1">[x{counter}]</b>
|
|
14
|
+
<span> {message}</span>
|
|
15
|
+
<a class="mx-1" href="{link}" ui:if="link">link</a>
|
|
16
|
+
</p>
|
|
11
17
|
</div>
|
|
12
|
-
</component>
|
|
13
|
-
|
|
18
|
+
</component>
|