icfs 0.2.0 → 0.3.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.
- checksums.yaml +4 -4
- data/data/icfs.css +7 -1
- data/data/icfs.js +17 -19
- data/devel/run/base.rb +2 -1
- data/devel/run/case-backup.rb +24 -0
- data/devel/run/case-restore.rb +24 -0
- data/devel/run/copy-s3.rb +2 -0
- data/devel/run/init-icfs.rb +7 -37
- data/devel/run/init-template.rb +33 -0
- data/lib/icfs/api.rb +92 -48
- data/lib/icfs/cache_elastic.rb +10 -2
- data/lib/icfs/config.rb +4 -3
- data/lib/icfs/items.rb +21 -5
- data/lib/icfs/utils/backup.rb +22 -18
- data/lib/icfs/utils/check.rb +24 -22
- data/lib/icfs/web/client.rb +302 -160
- data/lib/icfs.rb +70 -1
- metadata +5 -3
- data/bin/icfs_demo_fcgi.rb +0 -53
data/lib/icfs/web/client.rb
CHANGED
@@ -169,6 +169,7 @@ class Client
|
|
169
169
|
when 'case_edit'; return _call_case_edit(env)
|
170
170
|
when 'entry_edit'; return _call_entry_edit(env)
|
171
171
|
when 'index_edit'; return _call_index_edit(env)
|
172
|
+
when 'action_edit'; return _call_action_edit(env)
|
172
173
|
when 'config_edit'; return _call_config_edit(env)
|
173
174
|
|
174
175
|
# view
|
@@ -304,6 +305,7 @@ class Client
|
|
304
305
|
['tags', :tags, :string].freeze,
|
305
306
|
['caseid', :caseid, :string].freeze,
|
306
307
|
['action', :action, :integer].freeze,
|
308
|
+
['index', :index, :integer].freeze,
|
307
309
|
['after', :after, :time].freeze,
|
308
310
|
['before', :before, :time].freeze,
|
309
311
|
['stat', :stat, :string].freeze,
|
@@ -322,7 +324,7 @@ class Client
|
|
322
324
|
[:action, :current].freeze,
|
323
325
|
[:time, :entry].freeze,
|
324
326
|
[:tags, nil].freeze,
|
325
|
-
[:
|
327
|
+
[:indexes, nil].freeze,
|
326
328
|
[:files, nil].freeze,
|
327
329
|
[:stats, nil].freeze,
|
328
330
|
[:title, :entry].freeze,
|
@@ -336,6 +338,7 @@ class Client
|
|
336
338
|
['after', :after, :time].freeze,
|
337
339
|
['before', :before, :time].freeze,
|
338
340
|
['user', :user, :string].freeze,
|
341
|
+
['case_edit', :case_edit, :boolean].freeze,
|
339
342
|
['entry', :entry, :integer].freeze,
|
340
343
|
['index', :index, :integer].freeze,
|
341
344
|
['action', :action, :integer].freeze,
|
@@ -355,6 +358,7 @@ class Client
|
|
355
358
|
[:entry, :log].freeze,
|
356
359
|
[:action, :log].freeze,
|
357
360
|
[:index, :log].freeze,
|
361
|
+
[:case, :log].freeze,
|
358
362
|
].freeze
|
359
363
|
|
360
364
|
|
@@ -541,9 +545,9 @@ class Client
|
|
541
545
|
tpl = api.case_read(tid)
|
542
546
|
tpl['title'] = ''
|
543
547
|
parts = [
|
544
|
-
_form_entry(env, tid, nil),
|
545
548
|
_form_create(env),
|
546
549
|
_form_case(env, tpl),
|
550
|
+
_form_entry(env, tid, nil),
|
547
551
|
]
|
548
552
|
body = [
|
549
553
|
_div_nav(env),
|
@@ -593,8 +597,8 @@ class Client
|
|
593
597
|
if env['REQUEST_METHOD'] == 'GET'
|
594
598
|
cse = api.case_read(cid)
|
595
599
|
parts = [
|
596
|
-
_form_entry(env, cid, nil),
|
597
600
|
_form_case(env, cse),
|
601
|
+
_form_entry(env, cid, nil, {enable: false}),
|
598
602
|
]
|
599
603
|
body = [
|
600
604
|
_div_nav(env),
|
@@ -610,19 +614,18 @@ class Client
|
|
610
614
|
# process
|
611
615
|
cse = _post_case(env, para)
|
612
616
|
ent = _post_entry(env, para)
|
613
|
-
|
614
|
-
if act.is_a?(Integer)
|
615
|
-
ent['action'] = act if act != 0
|
616
|
-
act = nil
|
617
|
-
end
|
618
|
-
ent['caseid'] = cid
|
617
|
+
cse['caseid'] = cid
|
619
618
|
cse_old = api.case_read(cid)
|
620
619
|
cse['template'] = cse_old['template']
|
621
|
-
api.record(ent,
|
620
|
+
api.record(ent, nil, nil, cse)
|
622
621
|
|
623
622
|
# display the case
|
624
|
-
body =
|
625
|
-
|
623
|
+
body = [
|
624
|
+
_div_nav(env),
|
625
|
+
_div_case(env, cse),
|
626
|
+
]
|
627
|
+
body << _div_entry(env, ent) if ent
|
628
|
+
return _resp_success(env, body.join(''))
|
626
629
|
end
|
627
630
|
end # def _call_case_edit()
|
628
631
|
|
@@ -660,16 +663,14 @@ class Client
|
|
660
663
|
end
|
661
664
|
|
662
665
|
# build form
|
663
|
-
|
664
|
-
if
|
665
|
-
|
666
|
-
|
667
|
-
end
|
666
|
+
opts = {}
|
667
|
+
opts[:enable] = true if enum == 0
|
668
|
+
opts[:action] = anum if anum
|
669
|
+
parts = [ _form_entry(env, cid, ent, opts) ]
|
668
670
|
body = [
|
669
671
|
_div_nav(env),
|
670
672
|
_div_desc(desc, ''),
|
671
|
-
_div_form(env, '/entry_edit/', cid, parts,
|
672
|
-
'Record Entry'),
|
673
|
+
_div_form(env, '/entry_edit/', cid, parts, 'Record Entry'),
|
673
674
|
].join('')
|
674
675
|
return _resp_success(env, body)
|
675
676
|
|
@@ -679,20 +680,15 @@ class Client
|
|
679
680
|
|
680
681
|
# process
|
681
682
|
ent = _post_entry(env, para)
|
682
|
-
|
683
|
-
if act.is_a?(Integer)
|
684
|
-
ent['action'] = act if act != 0
|
685
|
-
act = nil
|
686
|
-
end
|
683
|
+
raise(Error::Values, 'Entry form not enabled') unless ent
|
687
684
|
ent['caseid'] = cid
|
688
|
-
api.record(ent,
|
685
|
+
api.record(ent, nil, nil, nil)
|
689
686
|
|
690
687
|
# display the entry
|
691
688
|
body = [
|
692
689
|
_div_nav(env),
|
693
690
|
_div_entry(env, ent)
|
694
691
|
]
|
695
|
-
body << _div_action(env, act) if act
|
696
692
|
return _resp_success(env, body.join(''))
|
697
693
|
end
|
698
694
|
end # def _call_entry_edit()
|
@@ -719,8 +715,8 @@ class Client
|
|
719
715
|
xnum = _util_num(env, 2)
|
720
716
|
idx = api.index_read(cid, xnum) if xnum != 0
|
721
717
|
parts = [
|
722
|
-
_form_entry(env, cid, nil),
|
723
718
|
_form_index(env, cid, idx),
|
719
|
+
_form_entry(env, cid, nil, {enable: false}),
|
724
720
|
]
|
725
721
|
desc = idx ? 'Edit Index' : 'New Index'
|
726
722
|
body = [
|
@@ -737,24 +733,76 @@ class Client
|
|
737
733
|
|
738
734
|
# process
|
739
735
|
ent = _post_entry(env, para)
|
740
|
-
act = _post_action(env, para)
|
741
736
|
idx = _post_index(env, para)
|
742
|
-
|
743
|
-
|
744
|
-
act = nil
|
745
|
-
end
|
746
|
-
ent['caseid'] = cid
|
747
|
-
api.record(ent, act, idx, nil)
|
737
|
+
idx['caseid'] = cid
|
738
|
+
api.record(ent, nil, idx, nil)
|
748
739
|
|
749
740
|
# display the index
|
750
741
|
body = [
|
751
742
|
_div_nav(env),
|
752
|
-
|
753
|
-
|
743
|
+
_div_index(env, idx),
|
744
|
+
]
|
745
|
+
body << _div_entry(env, ent) if ent
|
746
|
+
return _resp_success(env, body.join(''))
|
747
|
+
end
|
748
|
+
end # def _call_index_edit()
|
749
|
+
|
750
|
+
|
751
|
+
###############################################
|
752
|
+
# Edit an Action
|
753
|
+
#
|
754
|
+
def _call_action_edit(env)
|
755
|
+
env['icfs.page'] = 'Action Edit'
|
756
|
+
api = env['icfs']
|
757
|
+
_verb_getpost(env)
|
758
|
+
|
759
|
+
cid = _util_case(env)
|
760
|
+
|
761
|
+
# get the form
|
762
|
+
if env['REQUEST_METHOD'] == 'GET'
|
763
|
+
anum = _util_num(env, 2)
|
764
|
+
|
765
|
+
# see if editing is possible
|
766
|
+
unless( api.access_list(cid).include?(ICFS::PermAction) ||
|
767
|
+
((anum != 0) && api.tasked?(cid, anum)) )
|
768
|
+
raise(Error::Perms, 'Not able to edit this action.')
|
769
|
+
end
|
770
|
+
|
771
|
+
act = api.action_read(cid, anum) if anum != 0
|
772
|
+
opts = {enable: false}
|
773
|
+
opts[:action] = anum if act
|
774
|
+
parts = [
|
775
|
+
_form_action(env, cid, act),
|
776
|
+
_form_entry(env, cid, nil, opts),
|
777
|
+
]
|
778
|
+
desc = act ? 'Edit Action' : 'New Action'
|
779
|
+
body = [
|
780
|
+
_div_nav(env),
|
781
|
+
_div_desc(desc, ''),
|
782
|
+
_div_form(env, '/action_edit/', cid, parts,
|
783
|
+
'Record Action'),
|
754
784
|
].join('')
|
755
785
|
return _resp_success(env, body)
|
786
|
+
|
787
|
+
# post the form
|
788
|
+
elsif env['REQUEST_METHOD'] == 'POST'
|
789
|
+
para = _util_post(env)
|
790
|
+
|
791
|
+
# process
|
792
|
+
ent = _post_entry(env, para)
|
793
|
+
act = _post_action(env, para)
|
794
|
+
act['caseid'] = cid
|
795
|
+
api.record(ent, act, nil, nil)
|
796
|
+
|
797
|
+
# display the index
|
798
|
+
body = [
|
799
|
+
_div_nav(env),
|
800
|
+
_div_action(env, act),
|
801
|
+
]
|
802
|
+
body << _div_entry(env, ent) if ent
|
803
|
+
return _resp_success(env, body.join(''))
|
756
804
|
end
|
757
|
-
end # def
|
805
|
+
end # def _call_action_edit()
|
758
806
|
|
759
807
|
|
760
808
|
###############################################
|
@@ -819,17 +867,15 @@ class Client
|
|
819
867
|
cid = _util_case(env)
|
820
868
|
lnum = _util_num(env, 2)
|
821
869
|
cse = api.case_read(cid, lnum)
|
822
|
-
|
823
|
-
|
824
|
-
else
|
825
|
-
msg = ''
|
826
|
-
end
|
870
|
+
ent = api.entry_read(cid, cse['entry']) if cse['entry']
|
871
|
+
msg = (lnum != 0) ? 'This is a historical version of this Case' : ''
|
827
872
|
body = [
|
828
873
|
_div_nav(env),
|
829
874
|
_div_desc('Case Information', msg),
|
830
875
|
_div_case(env, cse),
|
831
|
-
]
|
832
|
-
|
876
|
+
]
|
877
|
+
body << _div_entry(env, ent) if ent
|
878
|
+
return _resp_success(env, body.join(''))
|
833
879
|
end # def _call_case()
|
834
880
|
|
835
881
|
|
@@ -891,31 +937,37 @@ class Client
|
|
891
937
|
lnum = _util_num(env, 3)
|
892
938
|
raise(Error::Interface, 'No Action requested') if anum == 0
|
893
939
|
|
894
|
-
# get the action
|
895
940
|
act = api.action_read(cid, anum, lnum)
|
941
|
+
ent = api.entry_read(cid, act['entry']) if act['entry']
|
942
|
+
ent_div = _div_entry(env, ent) if ent
|
943
|
+
|
944
|
+
# historical
|
896
945
|
if lnum != 0
|
897
946
|
msg = 'This is a historical version of this Action'
|
947
|
+
list_div = ''
|
948
|
+
|
949
|
+
# current
|
898
950
|
else
|
899
951
|
msg = ''
|
952
|
+
query = {
|
953
|
+
caseid: cid,
|
954
|
+
action: anum,
|
955
|
+
purpose: 'Action Entries',
|
956
|
+
}
|
957
|
+
resp = api.entry_search(query)
|
958
|
+
list_div = _div_list(env, resp, ListEntry) +
|
959
|
+
_div_page(resp){|qu, txt| _a_entry_search(env, qu, txt)}
|
900
960
|
end
|
901
961
|
|
902
|
-
# get the entries
|
903
|
-
query = {
|
904
|
-
caseid: cid,
|
905
|
-
action: anum,
|
906
|
-
purpose: 'Action Entries',
|
907
|
-
}
|
908
|
-
resp = api.entry_search(query)
|
909
|
-
|
910
962
|
# display
|
911
963
|
body = [
|
912
964
|
_div_nav(env),
|
913
965
|
_div_desc('View Action', msg),
|
914
966
|
_div_action(env, act),
|
915
|
-
|
916
|
-
|
917
|
-
]
|
918
|
-
return _resp_success(env, body)
|
967
|
+
ent_div,
|
968
|
+
list_div
|
969
|
+
]
|
970
|
+
return _resp_success(env, body.join(''))
|
919
971
|
end # def _call_action()
|
920
972
|
|
921
973
|
|
@@ -931,30 +983,37 @@ class Client
|
|
931
983
|
lnum = _util_num(env, 3)
|
932
984
|
raise(Error::Interface, 'No Index requested') if xnum == 0
|
933
985
|
|
934
|
-
|
986
|
+
|
935
987
|
idx = api.index_read(cid, xnum, lnum)
|
988
|
+
ent = api.entry_read(cid, idx['entry']) if idx['entry']
|
989
|
+
ent_div = ent ? _div_entry(env, ent) : ''
|
990
|
+
|
991
|
+
# historical index
|
936
992
|
if lnum != 0
|
937
993
|
msg = 'This is a historical version of this Index'
|
994
|
+
list_div = ''
|
995
|
+
|
996
|
+
# current index
|
938
997
|
else
|
939
998
|
msg = ''
|
999
|
+
query = {
|
1000
|
+
caseid: cid,
|
1001
|
+
index: xnum
|
1002
|
+
}
|
1003
|
+
resp = api.entry_search(query)
|
1004
|
+
list_div = _div_list(env, resp, ListEntry) +
|
1005
|
+
_div_page(resp){|qu, txt| _a_entry_search(env, qu, txt)}
|
940
1006
|
end
|
941
1007
|
|
942
|
-
# get the entries
|
943
|
-
query = {
|
944
|
-
caseid: cid,
|
945
|
-
index: xnum
|
946
|
-
}
|
947
|
-
resp = api.entry_search(query)
|
948
|
-
|
949
1008
|
# display
|
950
1009
|
body = [
|
951
|
-
_div_nav(env)
|
1010
|
+
_div_nav(env),
|
952
1011
|
_div_desc('View Index', msg),
|
953
1012
|
_div_index(env, idx),
|
954
|
-
|
955
|
-
|
956
|
-
]
|
957
|
-
return _resp_success(env, body)
|
1013
|
+
ent_div,
|
1014
|
+
list_div
|
1015
|
+
]
|
1016
|
+
return _resp_success(env, body.join(''))
|
958
1017
|
end # def _call_index()
|
959
1018
|
|
960
1019
|
|
@@ -1177,17 +1236,19 @@ class Client
|
|
1177
1236
|
entry: 'list-int',
|
1178
1237
|
action: 'list-int',
|
1179
1238
|
index: 'list-int',
|
1239
|
+
indexes: 'list-int-sm',
|
1240
|
+
case: 'list-int',
|
1180
1241
|
log: 'list-int',
|
1181
|
-
tags: 'list-int',
|
1242
|
+
tags: 'list-int-sm',
|
1182
1243
|
tag: 'list-tag',
|
1183
|
-
stats: 'list-int',
|
1244
|
+
stats: 'list-int-sm',
|
1184
1245
|
time: 'list-time',
|
1185
1246
|
title: 'list-title',
|
1186
1247
|
caseid: 'list-caseid',
|
1187
1248
|
stat: 'list-stat',
|
1188
1249
|
sum: 'list-float',
|
1189
1250
|
count: 'list-int',
|
1190
|
-
files: 'list-int',
|
1251
|
+
files: 'list-int-sm',
|
1191
1252
|
user: 'list-usergrp',
|
1192
1253
|
}.freeze
|
1193
1254
|
|
@@ -1218,6 +1279,10 @@ class Client
|
|
1218
1279
|
end
|
1219
1280
|
head = DivListHead % hcols.join('')
|
1220
1281
|
|
1282
|
+
# do we do relative times?
|
1283
|
+
cfg = env['icfs'].config
|
1284
|
+
rel_time = cfg.get('rel_time')
|
1285
|
+
|
1221
1286
|
# search results into rows
|
1222
1287
|
rows = resp[:list].map do |sr|
|
1223
1288
|
obj = sr[:object]
|
@@ -1226,6 +1291,7 @@ class Client
|
|
1226
1291
|
cols = list.map do |sym, opt|
|
1227
1292
|
it = obj[sym]
|
1228
1293
|
cc = ListColClass[sym]
|
1294
|
+
ct = nil
|
1229
1295
|
|
1230
1296
|
# snippets are special non-column, not in the object itself
|
1231
1297
|
if sym == :snippet
|
@@ -1257,7 +1323,7 @@ class Client
|
|
1257
1323
|
when :current
|
1258
1324
|
cd = _a_entry(env, cid, it, 0, it.to_s)
|
1259
1325
|
when :log
|
1260
|
-
cd = _a_entry(env, cid, it, obj[:log], it.to_s)
|
1326
|
+
cd = (it != 0) ? _a_entry(env, cid, it, obj[:log], it.to_s) : ''
|
1261
1327
|
else
|
1262
1328
|
cd = it.to_s
|
1263
1329
|
end
|
@@ -1268,11 +1334,7 @@ class Client
|
|
1268
1334
|
when :current
|
1269
1335
|
cd = (it == 0) ? '' : _a_action(env, cid, it, 0, it.to_s)
|
1270
1336
|
when :log
|
1271
|
-
|
1272
|
-
cd = _a_action(env, cid, it, obj[:log], it.to_s)
|
1273
|
-
else
|
1274
|
-
cd = ''
|
1275
|
-
end
|
1337
|
+
cd = (it != 0) ? _a_action(env, cid, it, obj[:log], it.to_s) : ''
|
1276
1338
|
else
|
1277
1339
|
cd = it == 0 ? '' : it.to_s
|
1278
1340
|
end
|
@@ -1280,8 +1342,6 @@ class Client
|
|
1280
1342
|
# index
|
1281
1343
|
when :index
|
1282
1344
|
case opt
|
1283
|
-
when :entry
|
1284
|
-
cd = (it == 0) ? '' : it.to_s
|
1285
1345
|
when :current
|
1286
1346
|
cd = _a_index(env, cid, it, 0, it.to_s)
|
1287
1347
|
when :log
|
@@ -1294,8 +1354,21 @@ class Client
|
|
1294
1354
|
cd = it.to_s
|
1295
1355
|
end
|
1296
1356
|
|
1357
|
+
# case
|
1358
|
+
when :case
|
1359
|
+
case opt
|
1360
|
+
when :log
|
1361
|
+
cd = (it != 0) ? _a_case(env, cid, obj[:log], 'Y') : ''
|
1362
|
+
else
|
1363
|
+
cd = ''
|
1364
|
+
end
|
1365
|
+
|
1366
|
+
# indexes
|
1367
|
+
when :indexes
|
1368
|
+
cd = (it == 0) ? '' : it.to_s
|
1369
|
+
|
1297
1370
|
# log
|
1298
|
-
|
1371
|
+
when :log
|
1299
1372
|
case opt
|
1300
1373
|
when :link
|
1301
1374
|
cd = _a_log(env, cid, it, it.to_s)
|
@@ -1332,13 +1405,20 @@ class Client
|
|
1332
1405
|
|
1333
1406
|
# time
|
1334
1407
|
when :time
|
1408
|
+
if rel_time
|
1409
|
+
tme = ICFS.time_relative(it)
|
1410
|
+
ct = ICFS.time_weekday(it, cfg)
|
1411
|
+
else
|
1412
|
+
tme = ICFS.time_weekday(it, cfg)
|
1413
|
+
end
|
1414
|
+
|
1335
1415
|
case opt
|
1336
1416
|
when :entry
|
1337
|
-
cd = _a_entry(env, cid, obj[:entry], 0,
|
1417
|
+
cd = _a_entry(env, cid, obj[:entry], 0, tme)
|
1338
1418
|
when :log
|
1339
|
-
cd = _a_log(env, cid, obj[:log],
|
1419
|
+
cd = _a_log(env, cid, obj[:log], tme)
|
1340
1420
|
else
|
1341
|
-
cd =
|
1421
|
+
cd = tme
|
1342
1422
|
end
|
1343
1423
|
|
1344
1424
|
# title
|
@@ -1400,7 +1480,15 @@ class Client
|
|
1400
1480
|
raise NotImplementedError, sym.to_s
|
1401
1481
|
end
|
1402
1482
|
|
1403
|
-
|
1483
|
+
if cd
|
1484
|
+
if ct
|
1485
|
+
DivListItemTitle % [cc, ct, cd]
|
1486
|
+
else
|
1487
|
+
DivListItem % [cc, cd]
|
1488
|
+
end
|
1489
|
+
else
|
1490
|
+
''
|
1491
|
+
end
|
1404
1492
|
end
|
1405
1493
|
|
1406
1494
|
DivListRow % cols.join('')
|
@@ -1429,15 +1517,19 @@ class Client
|
|
1429
1517
|
# Search results header items
|
1430
1518
|
DivListHeadItems = {
|
1431
1519
|
tags: '
|
1432
|
-
<div class="list-int"
|
1520
|
+
<div class="list-int-sm" title="Number of tags">#T</div>',
|
1433
1521
|
tag: '
|
1434
1522
|
<div class="list-tag">Tag</div>',
|
1435
1523
|
entry: '
|
1436
1524
|
<div class="list-int">Entry</div>',
|
1437
1525
|
index: '
|
1438
1526
|
<div class="list-int">Index</div>',
|
1527
|
+
indexes: '
|
1528
|
+
<div class="list-int-sm" title="Number of Indexes">#I</div>',
|
1439
1529
|
action: '
|
1440
1530
|
<div class="list-int">Action</div>',
|
1531
|
+
case: '
|
1532
|
+
<div class="list-int">Case</div>',
|
1441
1533
|
log: '
|
1442
1534
|
<div class="list-int">Log</div>',
|
1443
1535
|
title: '
|
@@ -1445,7 +1537,7 @@ class Client
|
|
1445
1537
|
caseid: '
|
1446
1538
|
<div class="list-caseid">Case ID</div>',
|
1447
1539
|
stats: '
|
1448
|
-
<div class="list-int"
|
1540
|
+
<div class="list-int-sm" title="Number of stats">#S</div>',
|
1449
1541
|
time: '
|
1450
1542
|
<div class="list-time">Date/Time</div>',
|
1451
1543
|
stat: '
|
@@ -1455,7 +1547,7 @@ class Client
|
|
1455
1547
|
count: '
|
1456
1548
|
<div class="list-int">Count</div>',
|
1457
1549
|
files: '
|
1458
|
-
<div class="list-int"
|
1550
|
+
<div class="list-int-sm" title="Number of files">#F</div>',
|
1459
1551
|
user: '
|
1460
1552
|
<div class="list-usergrp">User</div>',
|
1461
1553
|
snippet: ''
|
@@ -1465,6 +1557,10 @@ class Client
|
|
1465
1557
|
DivListItem = '
|
1466
1558
|
<div class="%s">%s</div>'
|
1467
1559
|
|
1560
|
+
# search results item with title
|
1561
|
+
DivListItemTitle = '
|
1562
|
+
<div class="%s" title="%s">%s</div>'
|
1563
|
+
|
1468
1564
|
|
1469
1565
|
###############################################
|
1470
1566
|
# Page description div
|
@@ -1779,7 +1875,8 @@ class Client
|
|
1779
1875
|
|
1780
1876
|
# case links
|
1781
1877
|
links = [
|
1782
|
-
_a_log_search(env, {caseid: cid}, 'History of Case'),
|
1878
|
+
_a_log_search(env, {caseid: cid, case_edit: true}, 'History of Case'),
|
1879
|
+
_a_log_search(env, {caseid: cid}, 'All Logs'),
|
1783
1880
|
]
|
1784
1881
|
if al.include?(ICFS::PermManage)
|
1785
1882
|
links << _a_case_edit(env, cid, 'Edit This Case')
|
@@ -1793,13 +1890,14 @@ class Client
|
|
1793
1890
|
if al.include?(ICFS::PermAction)
|
1794
1891
|
now = Time.now.to_i
|
1795
1892
|
actions = [
|
1893
|
+
_a_action_edit(env, cid, 0, 'New Action'),
|
1796
1894
|
_a_action_search(env, {
|
1797
1895
|
caseid: cid,
|
1798
1896
|
assigned: ICFS::UserCase,
|
1799
1897
|
status: true,
|
1800
1898
|
flag: true,
|
1801
1899
|
purpose: 'Flagged Actions',
|
1802
|
-
}, 'flagged'),
|
1900
|
+
}, 'List flagged'),
|
1803
1901
|
_a_action_search(env, {
|
1804
1902
|
caseid: cid,
|
1805
1903
|
assigned: ICFS::UserCase,
|
@@ -1807,7 +1905,7 @@ class Client
|
|
1807
1905
|
before: now,
|
1808
1906
|
sort: 'time_asc',
|
1809
1907
|
purpose: 'Actions - Past Date',
|
1810
|
-
}, 'past'),
|
1908
|
+
}, 'List past'),
|
1811
1909
|
_a_action_search(env, {
|
1812
1910
|
caseid: cid,
|
1813
1911
|
assigned: ICFS::UserCase,
|
@@ -1815,19 +1913,19 @@ class Client
|
|
1815
1913
|
after: now,
|
1816
1914
|
sort: 'time_desc',
|
1817
1915
|
purpose: 'Actions - Future Date',
|
1818
|
-
}, 'future'),
|
1916
|
+
}, 'List future'),
|
1819
1917
|
_a_action_search(env, {
|
1820
1918
|
caseid: cid,
|
1821
1919
|
assigned: ICFS::UserCase,
|
1822
1920
|
status: true,
|
1823
1921
|
purpose: 'Open Actions',
|
1824
|
-
}, '
|
1922
|
+
}, 'List open'),
|
1825
1923
|
_a_action_tags(env, {
|
1826
1924
|
caseid: cid,
|
1827
1925
|
assigned: ICFS::UserCase,
|
1828
1926
|
status: true,
|
1829
1927
|
purpose: 'Open Action Tags',
|
1830
|
-
}, 'tags'),
|
1928
|
+
}, 'Action tags'),
|
1831
1929
|
].map{|lk| DivCaseLink % lk}
|
1832
1930
|
actions = DivCaseActions % actions.join('')
|
1833
1931
|
else
|
@@ -2051,7 +2149,7 @@ class Client
|
|
2051
2149
|
action,
|
2052
2150
|
links.map{|lk| DivEntryLink % lk }.join(''),
|
2053
2151
|
Rack::Utils.escape_html(ent['title']),
|
2054
|
-
|
2152
|
+
ICFS.time_weekday(ent['time'], api.config),
|
2055
2153
|
Rack::Utils.escape_html(ent['content']),
|
2056
2154
|
tags.join("\n"),
|
2057
2155
|
index,
|
@@ -2181,19 +2279,26 @@ class Client
|
|
2181
2279
|
def _div_log(env, log)
|
2182
2280
|
cid = log['caseid']
|
2183
2281
|
lnum = log['log']
|
2184
|
-
enum = log['entry']['num']
|
2185
2282
|
|
2186
2283
|
navp = (lnum == 1) ? 'prev' : _a_log(env, cid, lnum-1, 'prev')
|
2187
2284
|
navn = _a_log(env, cid, lnum + 1, 'next')
|
2188
2285
|
|
2189
|
-
|
2190
|
-
|
2191
|
-
if log['case_hash']
|
2192
|
-
chash = DivLogCase % _a_case(env, cid, lnum, log['case_hash'])
|
2286
|
+
if log['case']
|
2287
|
+
chash = DivLogCase % _a_case(env, cid, lnum, log['case']['hash'])
|
2193
2288
|
else
|
2194
2289
|
chash = ''
|
2195
2290
|
end
|
2196
2291
|
|
2292
|
+
if log['entry']
|
2293
|
+
enum = log['entry']['num']
|
2294
|
+
entry = DivLogEntry % [
|
2295
|
+
_a_entry(env, cid, enum, lnum, log['entry']['hash']),
|
2296
|
+
enum
|
2297
|
+
]
|
2298
|
+
else
|
2299
|
+
entry = ''
|
2300
|
+
end
|
2301
|
+
|
2197
2302
|
if log['action']
|
2198
2303
|
action = DivLogAction % [
|
2199
2304
|
_a_action(env, cid, log['action']['num'], lnum, log['action']['hash']),
|
@@ -2231,11 +2336,10 @@ class Client
|
|
2231
2336
|
log['log'],
|
2232
2337
|
navp,
|
2233
2338
|
navn,
|
2234
|
-
|
2339
|
+
ICFS.time_weekday(log['time'], env['icfs'].config),
|
2235
2340
|
Rack::Utils.escape_html(log['user']),
|
2236
2341
|
log['prev'],
|
2237
|
-
|
2238
|
-
enum,
|
2342
|
+
entry,
|
2239
2343
|
chash,
|
2240
2344
|
action,
|
2241
2345
|
index,
|
@@ -2275,14 +2379,18 @@ class Client
|
|
2275
2379
|
<div class="list-row">
|
2276
2380
|
<div class="list-label">Prev:</div>
|
2277
2381
|
<div class="list-hash">%s</div>
|
2278
|
-
</div
|
2382
|
+
</div>%s%s%s%s%s
|
2383
|
+
</div>
|
2384
|
+
</div>'
|
2385
|
+
|
2386
|
+
|
2387
|
+
# log entry
|
2388
|
+
DivLogEntry = '
|
2279
2389
|
<div class="list-row">
|
2280
2390
|
<div class="list-label">Entry:</div>
|
2281
2391
|
<div class="list-hash">%s</div>
|
2282
2392
|
<div class="list-int">%d</div>
|
2283
|
-
</div
|
2284
|
-
</div>
|
2285
|
-
</div>'
|
2393
|
+
</div>'
|
2286
2394
|
|
2287
2395
|
|
2288
2396
|
# log action
|
@@ -2344,7 +2452,7 @@ class Client
|
|
2344
2452
|
|
2345
2453
|
links = []
|
2346
2454
|
anum = act['action']
|
2347
|
-
links <<
|
2455
|
+
links << _a_action_edit(env, cid, anum, 'Edit this Action')
|
2348
2456
|
|
2349
2457
|
lnum = act['log']
|
2350
2458
|
links << _a_log_search(env, {
|
@@ -2353,6 +2461,8 @@ class Client
|
|
2353
2461
|
'purpose' => 'Action History',
|
2354
2462
|
}, 'History of Action')
|
2355
2463
|
|
2464
|
+
links << _a_entry_edit(env, cid, 0, anum, 'New Entry in Action')
|
2465
|
+
|
2356
2466
|
# each task
|
2357
2467
|
tasks = []
|
2358
2468
|
ta = act['tasks']
|
@@ -2379,7 +2489,7 @@ class Client
|
|
2379
2489
|
Rack::Utils.escape_html(tk['title']),
|
2380
2490
|
tk['status'] ? 'Open' : 'Closed',
|
2381
2491
|
tk['flag'] ? 'Raised' : 'Normal',
|
2382
|
-
|
2492
|
+
ICFS.time_weekday(tk['time'], api.config),
|
2383
2493
|
tags.join(''),
|
2384
2494
|
]
|
2385
2495
|
end
|
@@ -2549,6 +2659,7 @@ class Client
|
|
2549
2659
|
# Description div for queries
|
2550
2660
|
#
|
2551
2661
|
def _div_query(env, type, sup, query, disp=false)
|
2662
|
+
cfg = env['icfs'].config
|
2552
2663
|
|
2553
2664
|
# query purpose
|
2554
2665
|
if query[:purpose]
|
@@ -2571,7 +2682,7 @@ class Client
|
|
2571
2682
|
when :integer
|
2572
2683
|
para = val.to_s
|
2573
2684
|
when :time
|
2574
|
-
para =
|
2685
|
+
para = ICFS.time_local(val, cfg)
|
2575
2686
|
else
|
2576
2687
|
raise NotImplementedError, pr.to_s
|
2577
2688
|
end
|
@@ -2613,6 +2724,7 @@ class Client
|
|
2613
2724
|
# Query form
|
2614
2725
|
#
|
2615
2726
|
def _form_query(env, sup, query, act, disp=false)
|
2727
|
+
cfg = env['icfs'].config
|
2616
2728
|
|
2617
2729
|
# supported params
|
2618
2730
|
inputs = sup.map do |txt, sym, pr|
|
@@ -2678,6 +2790,10 @@ class Client
|
|
2678
2790
|
ilabel = 'Permission'
|
2679
2791
|
iclass = 'form-perm'
|
2680
2792
|
ihint = 'Filter for cases granting this permission.'
|
2793
|
+
when :case_edit
|
2794
|
+
ilabel = 'Case edited'
|
2795
|
+
iclass = 'form-boolean'
|
2796
|
+
ihint = 'Filter for logs recoding a case.'
|
2681
2797
|
when :entry
|
2682
2798
|
ilabel = 'Entry'
|
2683
2799
|
iclass = 'form-int'
|
@@ -2726,7 +2842,7 @@ class Client
|
|
2726
2842
|
ivalue = query[sym] ? query[sym].to_s : ''
|
2727
2843
|
when :time
|
2728
2844
|
itype = 'text'
|
2729
|
-
ivalue = query[sym] ?
|
2845
|
+
ivalue = query[sym] ? ICFS.time_local(query[sym], cfg) : ''
|
2730
2846
|
else
|
2731
2847
|
raise NotImplementedError, pr.to_s
|
2732
2848
|
end
|
@@ -2945,7 +3061,13 @@ class Client
|
|
2945
3061
|
#############################################
|
2946
3062
|
# New entry form
|
2947
3063
|
#
|
2948
|
-
|
3064
|
+
# @param env [Hash] Rack enviornment
|
3065
|
+
# @param cid [String] caseid
|
3066
|
+
# @param ent [Hash] the Entry
|
3067
|
+
# @param opts [Hash] options
|
3068
|
+
#
|
3069
|
+
#
|
3070
|
+
def _form_entry(env, cid, ent=nil, opts={})
|
2949
3071
|
api = env['icfs']
|
2950
3072
|
|
2951
3073
|
# title
|
@@ -2957,11 +3079,20 @@ class Client
|
|
2957
3079
|
|
2958
3080
|
# time
|
2959
3081
|
if ent && ent['time']
|
2960
|
-
time =
|
3082
|
+
time = ICFS.time_local(ent['time'], api.config)
|
2961
3083
|
else
|
2962
3084
|
time = ''
|
2963
3085
|
end
|
2964
3086
|
|
3087
|
+
# action
|
3088
|
+
if opts[:action]
|
3089
|
+
anum = opts[:action]
|
3090
|
+
elsif ent && ent['action']
|
3091
|
+
anum = ent['action']
|
3092
|
+
else
|
3093
|
+
anum = 0
|
3094
|
+
end
|
3095
|
+
|
2965
3096
|
# content
|
2966
3097
|
if ent && ent['content']
|
2967
3098
|
content = Rack::Utils.escape_html(ent['content'])
|
@@ -3070,8 +3201,11 @@ class Client
|
|
3070
3201
|
end
|
3071
3202
|
|
3072
3203
|
return FormEntry % [
|
3204
|
+
opts[:enable] ? 'true' : 'false',
|
3073
3205
|
ent ? ent['entry'] : 0,
|
3074
|
-
|
3206
|
+
anum,
|
3207
|
+
opts[:enable] ? '' : FormEntryEnable,
|
3208
|
+
opts[:enable] ? '' : ' hidden',
|
3075
3209
|
title, time, content,
|
3076
3210
|
tags_cnt, tags,
|
3077
3211
|
files_cnt, files,
|
@@ -3084,6 +3218,15 @@ class Client
|
|
3084
3218
|
end # def _form_entry
|
3085
3219
|
|
3086
3220
|
|
3221
|
+
# entry toggle button
|
3222
|
+
FormEntryEnable = '
|
3223
|
+
<div class="sect-right">
|
3224
|
+
<button id="ent-ena-button" class="ent-ena" type="button"
|
3225
|
+
onclick="entEnable()">Toggle Edit
|
3226
|
+
</button>
|
3227
|
+
</div>'.freeze
|
3228
|
+
|
3229
|
+
|
3087
3230
|
# entry edit form
|
3088
3231
|
FormEntry = '
|
3089
3232
|
<div class="sect">
|
@@ -3093,9 +3236,14 @@ class Client
|
|
3093
3236
|
Describe the activity.
|
3094
3237
|
</div></div>
|
3095
3238
|
<div class="sect-fill"> </div>
|
3239
|
+
<input id="ent-ena" name="ent-ena" type="hidden" value="%s">
|
3096
3240
|
<input name="ent-num" type="hidden" value="%d">
|
3097
|
-
<input name="ent-act" type="hidden" value="%d"
|
3241
|
+
<input name="ent-act" type="hidden" value="%d">%s
|
3098
3242
|
</div>
|
3243
|
+
</div>
|
3244
|
+
<div id="ent-body" class="ent-body%s">
|
3245
|
+
|
3246
|
+
<div class="sect">
|
3099
3247
|
<div class="form-row">
|
3100
3248
|
<div class="list-label">Title:</div>
|
3101
3249
|
<input class="form-title" name="ent-title" type="text"
|
@@ -3210,6 +3358,7 @@ class Client
|
|
3210
3358
|
<input type="hidden" name="ent-perm-cnt" id="ent-perm-cnt" value="%d">
|
3211
3359
|
<div class="perms-list" id="ent-perm-list">%s
|
3212
3360
|
</div>
|
3361
|
+
</div>
|
3213
3362
|
</div>'
|
3214
3363
|
|
3215
3364
|
|
@@ -3295,8 +3444,9 @@ class Client
|
|
3295
3444
|
###############################################
|
3296
3445
|
# Action form
|
3297
3446
|
#
|
3298
|
-
def _form_action(env, cid, act = nil
|
3447
|
+
def _form_action(env, cid, act = nil)
|
3299
3448
|
api = env['icfs']
|
3449
|
+
cfg = api.config
|
3300
3450
|
|
3301
3451
|
# new action
|
3302
3452
|
if !act
|
@@ -3324,17 +3474,6 @@ class Client
|
|
3324
3474
|
ur.add api.user
|
3325
3475
|
ur.merge api.roles
|
3326
3476
|
|
3327
|
-
# editing
|
3328
|
-
if opt[:edit]
|
3329
|
-
ena_val = 'true'
|
3330
|
-
ena_class_add = ''
|
3331
|
-
ena_class_tasks = ''
|
3332
|
-
else
|
3333
|
-
ena_val = 'false'
|
3334
|
-
ena_class_add = ' invisible'
|
3335
|
-
ena_class_tasks = ' hidden'
|
3336
|
-
end
|
3337
|
-
|
3338
3477
|
# each task
|
3339
3478
|
tasks = []
|
3340
3479
|
ta.each_index do |ixr|
|
@@ -3361,7 +3500,7 @@ class Client
|
|
3361
3500
|
flag = FormActionFlagEd % [
|
3362
3501
|
ix, tk['flag'] ? ' checked' : '' ]
|
3363
3502
|
if tk['time']
|
3364
|
-
time = FormActionTimeEd % [ ix,
|
3503
|
+
time = FormActionTimeEd % [ ix, ICFS.time_local(tk['time'], cfg) ]
|
3365
3504
|
else
|
3366
3505
|
time = FormActionTimeEd % [ix, '']
|
3367
3506
|
end
|
@@ -3395,7 +3534,7 @@ class Client
|
|
3395
3534
|
else
|
3396
3535
|
flag = FormActionFlagEd % [ ix, '' ]
|
3397
3536
|
end
|
3398
|
-
esc =
|
3537
|
+
esc = ICFS.time_local(tk['time'], cfg)
|
3399
3538
|
time = FormActionTimeRo % [ ix, esc, esc ]
|
3400
3539
|
|
3401
3540
|
tags_cnt = 0
|
@@ -3422,11 +3561,8 @@ class Client
|
|
3422
3561
|
|
3423
3562
|
return FormAction % [
|
3424
3563
|
act ? act['action'] : 0,
|
3425
|
-
ena_class_add,
|
3426
|
-
ena_val,
|
3427
3564
|
tasks.size,
|
3428
3565
|
act ? act['action'] : 0,
|
3429
|
-
ena_class_tasks,
|
3430
3566
|
tasks.join('')
|
3431
3567
|
]
|
3432
3568
|
end # def _form_action()
|
@@ -3439,24 +3575,18 @@ class Client
|
|
3439
3575
|
<div class="sect-label">Action</div>
|
3440
3576
|
<div class="tip"><div class="tip-disp"></div><div class="tip-info">
|
3441
3577
|
A unit of work, accomplished in a set of related real-world
|
3442
|
-
and administrative
|
3578
|
+
and administrative activities.
|
3443
3579
|
</div></div>
|
3444
3580
|
<div class="sect-fill"> </div>
|
3445
3581
|
<input name="act-num" type="hidden" value="%d">
|
3446
|
-
<div class="sect-right">
|
3447
|
-
<button id="act-ena-button" class="act-ena" type="button"
|
3448
|
-
onclick="actEnable()">Toggle Edit
|
3449
|
-
</button>
|
3450
|
-
</div>
|
3451
|
-
<div id="act-task-add" class="sect-right%s">
|
3582
|
+
<div id="act-task-add" class="sect-right">
|
3452
3583
|
<button class="tsk-add" type="button" onclick="actAddTask()">+
|
3453
3584
|
</button>
|
3454
3585
|
</div>
|
3455
|
-
<input id="act-ena" name="act-ena" type="hidden" value="%s">
|
3456
3586
|
<input id="act-cnt" name="act-cnt" type="hidden" value="%d">
|
3457
3587
|
<input type="hidden" name="act-num" value="%d">
|
3458
3588
|
</div>
|
3459
|
-
<div id="act-tasks"
|
3589
|
+
<div id="act-tasks">%s
|
3460
3590
|
</div>
|
3461
3591
|
</div>'
|
3462
3592
|
|
@@ -3685,8 +3815,10 @@ class Client
|
|
3685
3815
|
# Config Form
|
3686
3816
|
#
|
3687
3817
|
def _form_config(env)
|
3688
|
-
|
3689
|
-
|
3818
|
+
cfg = env['icfs'].config
|
3819
|
+
tz = cfg.get('tz')
|
3820
|
+
rel_time = cfg.get('rel_time') ? 'true' : 'false'
|
3821
|
+
return FormConfig % [tz, rel_time]
|
3690
3822
|
end # def _form_config()
|
3691
3823
|
|
3692
3824
|
|
@@ -3707,6 +3839,13 @@ class Client
|
|
3707
3839
|
Timezone to display date/times, format as +/-HH:MM.
|
3708
3840
|
</div></div>
|
3709
3841
|
</div>
|
3842
|
+
<div class="form-row">
|
3843
|
+
<div class="list-label">Rel. Time:</div>
|
3844
|
+
<input class="form-boolean" name="cfg-reltime" type="text" value="%s">
|
3845
|
+
<div class="tip"><div class="tip-disp"></div><div class="tip-info">
|
3846
|
+
Display relative times e.g. 3 days ago.
|
3847
|
+
</div></div>
|
3848
|
+
</div>
|
3710
3849
|
</div>'
|
3711
3850
|
|
3712
3851
|
|
@@ -3800,6 +3939,8 @@ class Client
|
|
3800
3939
|
# Entry edit
|
3801
3940
|
#
|
3802
3941
|
def _post_entry(env, para)
|
3942
|
+
return nil unless para['ent-ena'] == 'true'
|
3943
|
+
|
3803
3944
|
api = env['icfs']
|
3804
3945
|
|
3805
3946
|
# entry object
|
@@ -3933,17 +4074,12 @@ class Client
|
|
3933
4074
|
# Action edit
|
3934
4075
|
#
|
3935
4076
|
def _post_action(env, para)
|
3936
|
-
|
3937
|
-
# action object
|
3938
4077
|
act = {}
|
3939
4078
|
|
3940
4079
|
# action
|
3941
4080
|
anum = para['act-num'].to_i
|
3942
4081
|
act['action'] = anum if anum != 0
|
3943
4082
|
|
3944
|
-
# any edit?
|
3945
|
-
return anum unless para['act-ena'] == 'true'
|
3946
|
-
|
3947
4083
|
# tasks
|
3948
4084
|
tasks = []
|
3949
4085
|
acnt = para['act-cnt'].to_i
|
@@ -3952,6 +4088,7 @@ class Client
|
|
3952
4088
|
tx = 'act-%d' % [ix + 1]
|
3953
4089
|
|
3954
4090
|
ug = para[tx + '-task']
|
4091
|
+
next if ug.nil? || ug.empty?
|
3955
4092
|
title = para[tx + '-title']
|
3956
4093
|
status = (para[tx + '-status'] == 'true') ? true : false
|
3957
4094
|
flag = (para[tx + '-flag'] == 'true') ? true : false
|
@@ -4025,7 +4162,8 @@ class Client
|
|
4025
4162
|
#
|
4026
4163
|
def _post_config(env, para)
|
4027
4164
|
cfg = {
|
4028
|
-
'tz' => para['cfg-tz']
|
4165
|
+
'tz' => para['cfg-tz'],
|
4166
|
+
'rel_time' => (para['cfg-reltime'].downcase == 'true' ? true : false),
|
4029
4167
|
}
|
4030
4168
|
return cfg
|
4031
4169
|
end # def _post_config()
|
@@ -4212,6 +4350,19 @@ class Client
|
|
4212
4350
|
end
|
4213
4351
|
|
4214
4352
|
|
4353
|
+
###############################################
|
4354
|
+
# Link to Action edit
|
4355
|
+
#
|
4356
|
+
def _a_action_edit(env, cid, anum, txt)
|
4357
|
+
'<a href="%s/action_edit/%s/%d">%s</a>' % [
|
4358
|
+
env['SCRIPT_NAME'],
|
4359
|
+
Rack::Utils.escape(cid),
|
4360
|
+
anum,
|
4361
|
+
Rack::Utils.escape_html(txt)
|
4362
|
+
]
|
4363
|
+
end
|
4364
|
+
|
4365
|
+
|
4215
4366
|
###############################################
|
4216
4367
|
# Link to Config edit
|
4217
4368
|
#
|
@@ -4377,15 +4528,6 @@ class Client
|
|
4377
4528
|
end # def _util_num()
|
4378
4529
|
|
4379
4530
|
|
4380
|
-
###############################################
|
4381
|
-
# Epoch time as local
|
4382
|
-
#
|
4383
|
-
def _util_time(env, time)
|
4384
|
-
tz = env['icfs'].config.get('tz')
|
4385
|
-
Time.at(time).getlocal(tz).strftime('%F %T')
|
4386
|
-
end
|
4387
|
-
|
4388
|
-
|
4389
4531
|
###############################################
|
4390
4532
|
# Parse a provided time string
|
4391
4533
|
#
|
@@ -4429,7 +4571,7 @@ class Client
|
|
4429
4571
|
when :array
|
4430
4572
|
query[sym] = val.split(',').map{|aa| aa.strip}
|
4431
4573
|
when :boolean
|
4432
|
-
if val == 'true'
|
4574
|
+
if val.downcase == 'true'
|
4433
4575
|
query[sym] = true
|
4434
4576
|
elsif val == 'false'
|
4435
4577
|
query[sym] = false
|