icfs 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|