unisi 0.1.12__py3-none-any.whl → 0.1.14__py3-none-any.whl
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.
- unisi/common.py +123 -7
- unisi/containers.py +3 -3
- unisi/dbelements.py +155 -0
- unisi/guielements.py +8 -23
- unisi/kdb.py +336 -0
- unisi/multimon.py +18 -31
- unisi/proxy.py +3 -1
- unisi/reloader.py +2 -2
- unisi/server.py +10 -4
- unisi/tables.py +176 -56
- unisi/users.py +48 -38
- unisi/utils.py +30 -82
- unisi/web/css/{662.64dbc68c.css → 346.824522cf.css} +1 -1
- unisi/web/index.html +1 -1
- unisi/web/js/346.c574f9c3.js +2 -0
- unisi/web/js/app.4b51aa78.js +1 -0
- unisi/web/js/{vendor.d6797c01.js → vendor.eab68489.js} +2 -2
- {unisi-0.1.12.dist-info → unisi-0.1.14.dist-info}/METADATA +38 -16
- {unisi-0.1.12.dist-info → unisi-0.1.14.dist-info}/RECORD +21 -19
- {unisi-0.1.12.dist-info → unisi-0.1.14.dist-info}/WHEEL +1 -1
- unisi/web/js/662.5957b792.js +0 -1
- unisi/web/js/app.636fcf8d.js +0 -1
- {unisi-0.1.12.dist-info → unisi-0.1.14.dist-info}/licenses/LICENSE +0 -0
unisi/tables.py
CHANGED
@@ -1,75 +1,199 @@
|
|
1
1
|
from .guielements import Gui
|
2
|
+
from .common import references, set_defaults, Warning, pretty4
|
3
|
+
from .dbelements import Dblist
|
2
4
|
|
3
|
-
|
4
|
-
|
5
|
+
relation_mark = 'Ⓡ'
|
6
|
+
exclude_mark = '✘'
|
7
|
+
|
8
|
+
def iterate(iter, times):
|
9
|
+
for i, val in enumerate(iter):
|
10
|
+
if i == times:
|
11
|
+
return val
|
12
|
+
|
13
|
+
def accept_cell_value(table, dval):
|
14
|
+
value = dval['value']
|
5
15
|
if not isinstance(value, bool):
|
6
16
|
try:
|
7
17
|
value = float(value)
|
8
|
-
except
|
9
|
-
|
10
|
-
table
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
if isinstance(value, list):
|
17
|
-
if keyed:
|
18
|
-
table.rows = [row for row in table.rows if row[-1] not in value]
|
19
|
-
else:
|
20
|
-
value.sort(reverse=True)
|
21
|
-
for v in value:
|
22
|
-
del table.rows[v]
|
23
|
-
table.value = []
|
18
|
+
except:
|
19
|
+
pass
|
20
|
+
if hasattr(table,'id'):
|
21
|
+
dbt = table.rows.dbtable
|
22
|
+
in_node, field = table.index2node_relation(dval['cell'])
|
23
|
+
if in_node:
|
24
|
+
table_id = table.id
|
25
|
+
row_id = table.rows[dval['delta']][len(dbt.table_fields)]
|
24
26
|
else:
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
27
|
+
table_id = table.__link__[2]
|
28
|
+
row_id = dval['id']
|
29
|
+
dbt.db.update_row(table_id, row_id, {field: value}, in_node)
|
30
|
+
|
31
|
+
table.rows[dval['delta']][dval['cell']] = value
|
32
|
+
|
33
|
+
def delete_table_row(table, value):
|
34
|
+
if table.selected_list:
|
35
|
+
if hasattr(table, 'link') and table.filter:
|
36
|
+
link_table, rel_props, rel_name = table.__link__
|
37
|
+
if not isinstance(value, list):
|
38
|
+
value = [value]
|
39
|
+
table.rows.dbtable.delete_links(link_table.id, link_ids = value, index_name = rel_name)
|
40
|
+
table.__link_table_selection_changed__(link_table, link_table.value)
|
41
|
+
return table
|
42
|
+
elif isinstance(value, list):
|
43
|
+
value.sort(reverse = True)
|
44
|
+
for v in value:
|
45
|
+
del table.rows[v]
|
46
|
+
table.value = []
|
47
|
+
else:
|
48
|
+
del table.rows[value]
|
29
49
|
table.value = None
|
30
50
|
|
31
|
-
def append_table_row(table,
|
32
|
-
''' append has to return new row
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
new_row
|
51
|
+
def append_table_row(table, search_str):
|
52
|
+
''' append has to return new row, value is the search string value in the table'''
|
53
|
+
new_row = [None] * len(table.rows.dbtable.table_fields)
|
54
|
+
if getattr(table,'id', None):
|
55
|
+
id = table.rows.dbtable.list.append(new_row)
|
56
|
+
new_row.append(id)
|
57
|
+
if hasattr(table, 'link') and table.filter:
|
58
|
+
link_table, _, rel_name = table.__link__
|
59
|
+
for linked_id in link_table.selected_list:
|
60
|
+
relation = table.rows.dbtable.add_link(id, link_table.id, linked_id, link_index_name = rel_name)
|
61
|
+
new_row.extend(relation)
|
62
|
+
break
|
37
63
|
table.rows.append(new_row)
|
38
64
|
return new_row
|
39
65
|
|
66
|
+
def get_chunk(obj, start_index):
|
67
|
+
delta, data = obj.rows.get_delta_chunk(start_index)
|
68
|
+
return {'type': 'updates', 'index': delta, 'data': data}
|
69
|
+
|
40
70
|
class Table(Gui):
|
41
71
|
def __init__(self, *args, panda = None, **kwargs):
|
42
72
|
if panda is not None:
|
43
73
|
self.mutate(PandaTable(*args, panda=panda, **kwargs))
|
44
74
|
else:
|
45
|
-
super().__init__(*args, **kwargs)
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
if
|
51
|
-
self
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
75
|
+
super().__init__(*args, **kwargs)
|
76
|
+
set_defaults(self, dict(headers = [], type = 'table', value = None, rows = [], editing = False, dense = True))
|
77
|
+
self.__headers__ = self.headers[:]
|
78
|
+
if getattr(self,'id', None):
|
79
|
+
db = references.context_user().db
|
80
|
+
if db:
|
81
|
+
db.set_db_list(self)
|
82
|
+
else:
|
83
|
+
raise AssertionError('Config db_dir is not defined!')
|
84
|
+
self.get = get_chunk
|
85
|
+
has_link = hasattr(self, 'link')
|
86
|
+
set_defaults(self, {'filter': has_link, 'ids': False, 'search': ''})
|
87
|
+
if has_link:
|
88
|
+
prop_types = {}
|
89
|
+
rel_name = ''
|
90
|
+
match self.link:
|
91
|
+
case [link_table, prop_types, rel_name]: ...
|
92
|
+
case [link_table, prop_types]: ...
|
93
|
+
case link_table: ...
|
94
|
+
rel_name, rel_fields = self.rows.dbtable.get_rel_fields2(link_table.id, prop_types, rel_name)
|
95
|
+
if not hasattr(link_table, 'id'):
|
96
|
+
raise AttributeError('Linked table has to be persistent!')
|
97
|
+
self.__link__ = link_table, list(prop_types.keys()), rel_name
|
98
|
+
self.link = rel_fields
|
99
|
+
|
100
|
+
@references.handle(link_table,'changed')
|
101
|
+
def link_table_selection_changed(master_table, val, init = False):
|
102
|
+
lstvalue = val if isinstance(val, list) else [val] if val != None else []
|
103
|
+
if lstvalue:
|
104
|
+
link_ids = [link_table.rows[val][-1] for val in lstvalue]
|
105
|
+
link_rows = self.rows.dbtable.calc_linked_rows(rel_name, link_ids, self.filter, self.search)
|
106
|
+
else:
|
107
|
+
link_rows = Dblist(self.rows.dbtable, cache = [])
|
108
|
+
if self.filter:
|
109
|
+
self.clean_selection()
|
110
|
+
self.rows = link_rows
|
111
|
+
else:
|
112
|
+
selected_ids = [link_rows[i][-1] for i in range(len(link_rows))]
|
113
|
+
self.value = selected_ids
|
114
|
+
#restore table rows if they are not rows
|
115
|
+
if self.rows.cache is not None:
|
116
|
+
self.rows = self.rows.dbtable.get_init_list()
|
117
|
+
if not init:
|
118
|
+
master_table.accept(val)
|
119
|
+
return self
|
120
|
+
link_table_selection_changed(link_table, link_table.value, True)
|
121
|
+
self.__link_table_selection_changed__ = link_table_selection_changed
|
122
|
+
|
123
|
+
@references.handle(self,'filter')
|
124
|
+
def filter_status_changed(table, value):
|
125
|
+
self.filter = value
|
126
|
+
link_table_selection_changed(link_table, link_table.value, True)
|
127
|
+
self.calc_headers()
|
128
|
+
return self
|
129
|
+
|
130
|
+
@references.handle(self,'changed')
|
131
|
+
def changed_selection_causes__changing_links(self, new_value):
|
132
|
+
if link_table.value is not None and link_table.value != []:
|
133
|
+
#if link table is in multi mode, links are not editable
|
134
|
+
if not self.filter and not isinstance(link_table.value, list | tuple):
|
135
|
+
if self.editing:
|
136
|
+
actual = set(new_value if isinstance(new_value, list) else [] if new_value is None else [new_value])
|
137
|
+
old = set(self.value if isinstance(self.value, list) else ([] if self.value is None else [self.value]))
|
138
|
+
deselected = old - actual
|
139
|
+
if deselected:
|
140
|
+
self.rows.dbtable.delete_links(link_table.id, link_table.value, deselected)
|
141
|
+
selected = actual - old
|
142
|
+
if selected:
|
143
|
+
self.rows.dbtable.add_links(link_table.id, selected, link_table.value)
|
144
|
+
else:
|
145
|
+
return Warning('The linked table is not in edit mode', self)
|
146
|
+
return self.accept(new_value)
|
147
|
+
|
148
|
+
@references.handle(self,'search')
|
149
|
+
def search_changed(table, value):
|
150
|
+
self.search = value
|
151
|
+
if has_link:
|
152
|
+
link_table_selection_changed(link_table, link_table.value, True)
|
153
|
+
else:
|
154
|
+
self.rows = self.rows.dbtable.get_init_list(self.search)
|
155
|
+
return self
|
156
|
+
|
157
|
+
self.calc_headers()
|
158
|
+
|
159
|
+
elif hasattr(self,'ids'):
|
160
|
+
raise ValueError("Only persistent tables can have 'ids' option!")
|
56
161
|
|
57
162
|
if getattr(self,'edit', True):
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
self.append = append_table_row
|
62
|
-
if not hasattr(self,'modify'):
|
63
|
-
self.modify = accept_cell_value
|
64
|
-
|
163
|
+
set_defaults(self,{'delete': delete_table_row, 'append': append_table_row, 'modify': accept_cell_value})
|
164
|
+
|
165
|
+
@property
|
65
166
|
def selected_list(self):
|
66
167
|
return [self.value] if self.value != None else [] if type(self.value) == int else self.value
|
67
168
|
|
68
|
-
def
|
69
|
-
self.
|
70
|
-
self.value = [] if isinstance(self.value,(tuple, list)) else None
|
169
|
+
def clean_selection(self):
|
170
|
+
self.value = [] if isinstance(self.value,tuple | list) else None
|
71
171
|
return self
|
172
|
+
|
173
|
+
def calc_headers(self):
|
174
|
+
"""only for persistent"""
|
175
|
+
table_fields = self.rows.dbtable.table_fields
|
176
|
+
self.headers = self.__headers__[:] if self.__headers__ else [pretty4(prop)for prop in table_fields]
|
177
|
+
only_node_headers = len(self.headers) == len(table_fields)
|
178
|
+
if self.ids:
|
179
|
+
self.headers.insert(len(table_fields), 'ID')
|
180
|
+
elif self.filter:
|
181
|
+
self.headers.insert(len(table_fields), exclude_mark + 'ID')
|
182
|
+
if self.filter:
|
183
|
+
if only_node_headers:
|
184
|
+
self.headers.extend([relation_mark + pretty4(link_field) for link_field in self.link])
|
185
|
+
if self.ids:
|
186
|
+
self.headers.append(relation_mark + 'ID')
|
72
187
|
|
188
|
+
def index2node_relation(self, cell_index):
|
189
|
+
"""calculate delta to property of node or link for persistent"""
|
190
|
+
table_fields = self.rows.dbtable.table_fields
|
191
|
+
delta = cell_index - len(table_fields)
|
192
|
+
if delta < 0:
|
193
|
+
return True, iterate(table_fields, cell_index)
|
194
|
+
delta -= 1 #ID field
|
195
|
+
return False, iterate(self.link, delta)
|
196
|
+
|
73
197
|
def delete_panda_row(table, row_num):
|
74
198
|
df = table.__panda__
|
75
199
|
if row_num < 0 or row_num >= len(df):
|
@@ -99,17 +223,13 @@ class PandaTable(Table):
|
|
99
223
|
raise Exception('PandaTable has to get panda = pandaTable as an argument.')
|
100
224
|
self.headers = panda.columns.tolist()
|
101
225
|
if fix_headers:
|
102
|
-
self.headers = [header
|
226
|
+
self.headers = [pretty4(header) for header in self.headers]
|
103
227
|
self.rows = panda.values.tolist()
|
104
228
|
self.__panda__ = panda
|
105
229
|
|
106
230
|
if getattr(self,'edit', True):
|
107
|
-
|
108
|
-
|
109
|
-
if not hasattr(self,'append'):
|
110
|
-
self.append = append_panda_row
|
111
|
-
if not hasattr(self,'modify'):
|
112
|
-
self.modify = accept_panda_cell
|
231
|
+
set_defaults(self,{'delete': delete_panda_row, 'append': append_panda_row,
|
232
|
+
'modify': accept_panda_cell})
|
113
233
|
@property
|
114
234
|
def panda(self):
|
115
235
|
return getattr(self,'__panda__',None)
|
unisi/users.py
CHANGED
@@ -3,9 +3,15 @@ from .guielements import *
|
|
3
3
|
from .common import *
|
4
4
|
from .containers import Dialog, Screen
|
5
5
|
from .multimon import notify_monitor, logging_lock, run_external_process
|
6
|
+
from .kdb import Database
|
6
7
|
import sys, asyncio, logging, importlib
|
7
8
|
|
8
|
-
class User:
|
9
|
+
class User:
|
10
|
+
last_user = None
|
11
|
+
toolbar = []
|
12
|
+
sessions = {}
|
13
|
+
count = 0
|
14
|
+
|
9
15
|
def __init__(self, session: str, share = None):
|
10
16
|
self.session = session
|
11
17
|
self.active_dialog = None
|
@@ -30,12 +36,12 @@ class User:
|
|
30
36
|
|
31
37
|
self.monitor(session, share)
|
32
38
|
|
33
|
-
async def run_process(self, long_running_task, *args,
|
34
|
-
if
|
39
|
+
async def run_process(self, long_running_task, *args, progress_callback = None, **kwargs):
|
40
|
+
if progress_callback and notify_monitor and progress_callback != self.progress: #progress notifies the monitor
|
35
41
|
async def new_callback(value):
|
36
|
-
asyncio.gather(notify_monitor('e', self.session, self.last_message),
|
37
|
-
|
38
|
-
return await run_external_process(long_running_task, *args,
|
42
|
+
asyncio.gather(notify_monitor('e', self.session, self.last_message), progress_callback(value))
|
43
|
+
progress_callback = new_callback
|
44
|
+
return await run_external_process(long_running_task, *args, progress_callback = progress_callback, **kwargs)
|
39
45
|
|
40
46
|
async def broadcast(self, message):
|
41
47
|
screen = self.screen_module
|
@@ -62,16 +68,7 @@ class User:
|
|
62
68
|
if notify_monitor:
|
63
69
|
await notify_monitor('e', self.session, self.last_message)
|
64
70
|
|
65
|
-
def load_screen(self, file):
|
66
|
-
screen_vars = {
|
67
|
-
'icon' : None,
|
68
|
-
'prepare' : None,
|
69
|
-
'blocks' : [],
|
70
|
-
'header' : config.appname,
|
71
|
-
'toolbar' : [],
|
72
|
-
'order' : 0,
|
73
|
-
'reload': config.hot_reload
|
74
|
-
}
|
71
|
+
def load_screen(self, file):
|
75
72
|
name = file[:-3]
|
76
73
|
path = f'{screens_dir}{divpath}{file}'
|
77
74
|
spec = importlib.util.spec_from_file_location(name,path)
|
@@ -81,8 +78,8 @@ class User:
|
|
81
78
|
spec.loader.exec_module(module)
|
82
79
|
screen = Screen(getattr(module, 'name', ''))
|
83
80
|
#set system vars
|
84
|
-
for var in
|
85
|
-
setattr(screen, var, getattr(module,var,
|
81
|
+
for var, val in screen.defaults.items():
|
82
|
+
setattr(screen, var, getattr(module, var, val))
|
86
83
|
|
87
84
|
if screen.toolbar:
|
88
85
|
screen.toolbar += User.toolbar
|
@@ -122,7 +119,7 @@ class User:
|
|
122
119
|
self.screens.append(module)
|
123
120
|
|
124
121
|
if self.screens:
|
125
|
-
self.screens.sort(key=lambda s: s.order)
|
122
|
+
self.screens.sort(key=lambda s: s.screen.order)
|
126
123
|
main = self.screens[0]
|
127
124
|
if 'prepare' in dir(main):
|
128
125
|
main.prepare()
|
@@ -146,7 +143,6 @@ class User:
|
|
146
143
|
|
147
144
|
def set_screen(self,name):
|
148
145
|
return asyncio.run(self.process(ArgObject(block = 'root', element = None, value = name)))
|
149
|
-
|
150
146
|
async def result4message(self, message):
|
151
147
|
result = None
|
152
148
|
self.last_message = message
|
@@ -244,18 +240,20 @@ class User:
|
|
244
240
|
|
245
241
|
async def process_element(self, elem, message):
|
246
242
|
event = message.event
|
247
|
-
query = event == 'complete' or event == 'append'
|
248
|
-
|
243
|
+
query = event == 'complete' or event == 'append' or event == 'get'
|
249
244
|
handler = self.__handlers__.get((elem, event), None)
|
250
245
|
if handler:
|
251
246
|
return await self.eval_handler(handler, elem, message.value)
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
247
|
+
|
248
|
+
if hasattr(elem, event):
|
249
|
+
attr = getattr(elem, event)
|
250
|
+
if is_callable(attr):
|
251
|
+
result = await self.eval_handler(attr, elem, message.value)
|
252
|
+
if query:
|
253
|
+
result = Answer(event, message, result)
|
254
|
+
return result
|
255
|
+
#set attribute only for declared properties
|
256
|
+
setattr(elem, event, message.value)
|
259
257
|
elif event == 'changed':
|
260
258
|
elem.value = message.value
|
261
259
|
else:
|
@@ -284,12 +282,6 @@ class User:
|
|
284
282
|
logging.info(str)
|
285
283
|
func(level = logging.WARNING)
|
286
284
|
|
287
|
-
User.type = User
|
288
|
-
User.last_user = None
|
289
|
-
User.toolbar = []
|
290
|
-
User.sessions = {}
|
291
|
-
User.count = 0
|
292
|
-
|
293
285
|
def context_user():
|
294
286
|
return context_object(User)
|
295
287
|
|
@@ -297,10 +289,19 @@ def context_screen():
|
|
297
289
|
user = context_user()
|
298
290
|
return user.screen if user else None
|
299
291
|
|
292
|
+
def message_logger(str, type = 'error'):
|
293
|
+
user = context_user()
|
294
|
+
user.log(str, type)
|
295
|
+
|
296
|
+
references.context_user = context_user
|
297
|
+
|
298
|
+
User.db = Database(config.db_dir, message_logger) if config.db_dir else None
|
299
|
+
User.type = User
|
300
|
+
|
300
301
|
def make_user(request):
|
301
302
|
session = f'{request.remote}-{User.count}'
|
302
303
|
User.count += 1
|
303
|
-
if requested_connect := request.
|
304
|
+
if requested_connect := request.query_string if config.share else None:
|
304
305
|
user = User.sessions.get(requested_connect, None)
|
305
306
|
if not user:
|
306
307
|
error = f'Session id "{requested_connect}" is unknown. Connection refused!'
|
@@ -320,5 +321,14 @@ def make_user(request):
|
|
320
321
|
|
321
322
|
def handle(elem, event):
|
322
323
|
def h(fn):
|
323
|
-
|
324
|
-
|
324
|
+
key = elem, event
|
325
|
+
handler_map = User.last_user.__handlers__
|
326
|
+
func = handler_map.get(key, None)
|
327
|
+
if func:
|
328
|
+
handler_map[key] = lambda el, ev: compose_returns(func(el, ev), fn(el, ev))
|
329
|
+
else:
|
330
|
+
handler_map[key] = fn
|
331
|
+
return fn
|
332
|
+
return h
|
333
|
+
|
334
|
+
references.handle = handle
|
unisi/utils.py
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
import os, platform, requests,
|
1
|
+
import os, platform, requests, logging
|
2
|
+
from .common import set_defaults
|
3
|
+
from .containers import Screen
|
2
4
|
|
3
5
|
blocks_dir = 'blocks'
|
4
6
|
screens_dir = 'screens'
|
5
|
-
UpdateScreen = True
|
6
|
-
Redesign = 2
|
7
7
|
public_dirs = 'public_dirs'
|
8
8
|
testdir = 'autotest'
|
9
9
|
|
@@ -28,40 +28,36 @@ appname = 'Unisi app'
|
|
28
28
|
print("Config with default parameters is created!")
|
29
29
|
|
30
30
|
#setting config variables
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
31
|
+
set_defaults(config, dict(
|
32
|
+
autotest= False,
|
33
|
+
appname = 'Unisi app',
|
34
|
+
upload_dir = 'web',
|
35
|
+
logfile= None,
|
36
|
+
hot_reload = False,
|
37
|
+
mirror = False,
|
38
|
+
share = False,
|
39
|
+
profile = 0,
|
40
|
+
llm = None,
|
41
|
+
froze_time= None,
|
42
|
+
monitor_tick = 0.005,
|
43
|
+
pool = None,
|
44
|
+
db_dir = None
|
45
|
+
))
|
46
|
+
|
47
|
+
Screen.defaults = dict(
|
48
|
+
icon = None,
|
49
|
+
prepare = None,
|
50
|
+
blocks = [],
|
51
|
+
header = config.appname,
|
52
|
+
toolbar = [],
|
53
|
+
order = 0,
|
54
|
+
reload = config.hot_reload
|
55
|
+
)
|
56
|
+
|
49
57
|
if config.froze_time == 0:
|
58
|
+
print('froze_time in config.py can not be 0!')
|
50
59
|
config.froze_time = None
|
51
60
|
|
52
|
-
def context_object(target_type):
|
53
|
-
"""
|
54
|
-
Finds the first argument of a specific type in the current function call stack.
|
55
|
-
"""
|
56
|
-
frame = inspect.currentframe()
|
57
|
-
while frame:
|
58
|
-
args, _, _, values = inspect.getargvalues(frame)
|
59
|
-
if args and isinstance(values[args[0]], target_type):
|
60
|
-
return values[args[0]]
|
61
|
-
# Move to the previous frame in the call stack
|
62
|
-
frame = frame.f_back
|
63
|
-
return None
|
64
|
-
|
65
61
|
def is_screen_switch(message):
|
66
62
|
return message and message.block == 'root' and message.element is None
|
67
63
|
|
@@ -93,54 +89,6 @@ def cache_url(url):
|
|
93
89
|
file.close()
|
94
90
|
return fname
|
95
91
|
|
96
|
-
class Message:
|
97
|
-
def __init__(self, *gui_objects, user = None, type = 'update'):
|
98
|
-
self.type = type
|
99
|
-
if gui_objects:
|
100
|
-
self.updates = [{'data': gui} for gui in gui_objects]
|
101
|
-
if user:
|
102
|
-
self.fill_paths4(user)
|
103
|
-
|
104
|
-
def fill_paths4(self, user):
|
105
|
-
if hasattr(self, 'updates'):
|
106
|
-
invalid = []
|
107
|
-
for update in self.updates:
|
108
|
-
data = update["data"]
|
109
|
-
path = user.find_path(data)
|
110
|
-
if path:
|
111
|
-
update['path'] = path
|
112
|
-
else:
|
113
|
-
invalid.append(update)
|
114
|
-
user.log(f'Invalid element update {data.name}, type {data.type}.\n\
|
115
|
-
Such element not on the screen!')
|
116
|
-
for inv in invalid:
|
117
|
-
self.updates.remove(inv)
|
118
|
-
|
119
|
-
def contains(self, guiobj):
|
120
|
-
if hasattr(self, 'updates'):
|
121
|
-
for update in self.updates:
|
122
|
-
if guiobj is update['data']:
|
123
|
-
return True
|
124
|
-
|
125
|
-
def TypeMessage(type, value, *data, user = None):
|
126
|
-
message = Message(*data, user=user, type = type)
|
127
|
-
message.value = value
|
128
|
-
return message
|
129
|
-
|
130
|
-
def Warning(text, *data):
|
131
|
-
return TypeMessage('warning', text, *data)
|
132
|
-
|
133
|
-
def Error(text, *data):
|
134
|
-
return TypeMessage('error', text, *data)
|
135
|
-
|
136
|
-
def Info(text, *data):
|
137
|
-
return TypeMessage('info', text, *data)
|
138
|
-
|
139
|
-
def Answer(type, message, result):
|
140
|
-
ms = TypeMessage(type, result)
|
141
|
-
ms.message = message
|
142
|
-
return ms
|
143
|
-
|
144
92
|
def start_logging():
|
145
93
|
format = "%(asctime)s - %(levelname)s - %(message)s"
|
146
94
|
logfile = config.logfile
|
@@ -1 +1 @@
|
|
1
|
-
thead tr:first-child th{-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);position:sticky;top:0;z-index:1000}:root{--scrollbar-width-height:10px;--scrollbar-thumb-hover:#2176d2;--scrollbar-thumb-dark:#2176d2;--scrollbar-thumb-hover-dark:#2176d2}::-webkit-scrollbar{height:var(--scrollbar-width-height);width:var(--scrollbar-width-height)}::-webkit-scrollbar-track{box-shadow:inset 0 0 4px var(--scrollbar-track-dark)}::-webkit-scrollbar-corner{background:var(--scrollbar-track-dark)}::-webkit-scrollbar-thumb{background:var(--scrollbar-thumb-dark);border-radius:5px}::-webkit-scrollbar-thumb:hover{background:var(--scrollbar-thumb-hover-dark)}body[data-v-
|
1
|
+
thead tr:first-child th{-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);position:sticky;top:0;z-index:1000}:root{--scrollbar-width-height:10px;--scrollbar-thumb-hover:#2176d2;--scrollbar-thumb-dark:#2176d2;--scrollbar-thumb-hover-dark:#2176d2}::-webkit-scrollbar{height:var(--scrollbar-width-height);width:var(--scrollbar-width-height)}::-webkit-scrollbar-track{box-shadow:inset 0 0 4px var(--scrollbar-track-dark)}::-webkit-scrollbar-corner{background:var(--scrollbar-track-dark)}::-webkit-scrollbar-thumb{background:var(--scrollbar-thumb-dark);border-radius:5px}::-webkit-scrollbar-thumb:hover{background:var(--scrollbar-thumb-hover-dark)}body[data-v-6eb6b02a]{display:flex;justify-content:center}.custom-caption[data-v-6eb6b02a]{padding:5px!important}.web-camera-container[data-v-6eb6b02a]{align-items:center;border:1px solid #ccc;border-radius:4px;display:flex;flex-direction:column;justify-content:center;margin-bottom:2rem;margin-top:2rem;padding:2rem;width:500px}.web-camera-container .camera-button[data-v-6eb6b02a]{margin-bottom:2rem}.web-camera-container .camera-box .camera-shutter[data-v-6eb6b02a]{background-color:#fff;height:337.5px;opacity:0;position:absolute;width:450px}.web-camera-container .camera-box .camera-shutter.flash[data-v-6eb6b02a]{opacity:1}.web-camera-container .camera-shoot[data-v-6eb6b02a]{margin:1rem 0}.web-camera-container .camera-shoot button[data-v-6eb6b02a]{align-items:center;border-radius:100%;display:flex;height:60px;justify-content:center;width:60px}.web-camera-container .camera-shoot button img[data-v-6eb6b02a]{height:35px;object-fit:cover}.web-camera-container .camera-loading[data-v-6eb6b02a]{height:100%;margin:3rem 0 0 -1.2rem;min-height:150px;overflow:hidden;position:absolute;width:100%}.web-camera-container .camera-loading ul[data-v-6eb6b02a]{height:100%;margin:0;position:absolute;width:100%;z-index:999999}.web-camera-container .camera-loading .loader-circle[data-v-6eb6b02a]{display:block;height:14px;left:100%;margin:0 auto;padding:0;position:absolute;top:50%;transform:translateY(-50%);transform:translateX(-50%);width:100%}.web-camera-container .camera-loading .loader-circle li[data-v-6eb6b02a]{animation:preload-6eb6b02a 1s infinite;background:#999;border-radius:100%;display:block;float:left;height:10px;line-height:10px;margin:0 0 0 4px;padding:0;position:relative;top:-50%;width:10px}.web-camera-container .camera-loading .loader-circle li[data-v-6eb6b02a]:nth-child(2){animation-delay:.2s}.web-camera-container .camera-loading .loader-circle li[data-v-6eb6b02a]:nth-child(3){animation-delay:.4s}@keyframes preload-6eb6b02a{0%{opacity:1}50%{opacity:.4}to{opacity:1}}.q-tab__label{font-size:16px;font-weight:700}
|
unisi/web/index.html
CHANGED
@@ -1 +1 @@
|
|
1
|
-
<!DOCTYPE html><html><head><title>UNISI</title><meta charset=utf-8><meta name=description content="UNISI on Quasar"><meta name=format-detection content="telephone=no"><meta name=msapplication-tap-highlight content=no><meta name=viewport content="user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1,width=device-width"><link rel=icon type=image/png sizes=128x128 href=icons/favicon-128x128.png><link rel=icon type=image/png sizes=96x96 href=icons/favicon-96x96.png><link rel=icon type=image/png sizes=32x32 href=icons/favicon-32x32.png><link rel=icon type=image/png sizes=16x16 href=icons/favicon-16x16.png><link rel=icon type=image/ico href=favicon.ico><script defer src
|
1
|
+
<!DOCTYPE html><html><head><base href=/ ><title>UNISI</title><meta charset=utf-8><meta name=description content="UNISI on Quasar"><meta name=format-detection content="telephone=no"><meta name=msapplication-tap-highlight content=no><meta name=viewport content="user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1,width=device-width"><link rel=icon type=image/png sizes=128x128 href=icons/favicon-128x128.png><link rel=icon type=image/png sizes=96x96 href=icons/favicon-96x96.png><link rel=icon type=image/png sizes=32x32 href=icons/favicon-32x32.png><link rel=icon type=image/png sizes=16x16 href=icons/favicon-16x16.png><link rel=icon type=image/ico href=favicon.ico><script defer src=/js/vendor.eab68489.js></script><script defer src=/js/app.4b51aa78.js></script><link href=/css/vendor.9ed7638d.css rel=stylesheet><link href=/css/app.31d6cfe0.css rel=stylesheet></head><body><div id=q-app></div></body></html>
|