icfs 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- [:index, :entry].freeze,
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
- act = _post_action(env, para)
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, act, nil, cse)
620
+ api.record(ent, nil, nil, cse)
622
621
 
623
622
  # display the case
624
- body = _div_nav(env) + _div_case(env, cse)
625
- return _resp_success(env, body)
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
- parts = [ _form_entry(env, cid, ent) ]
664
- if !ent &&
665
- (act || api.access_list(cid).include?(ICFS::PermAction))
666
- parts << _form_action(env, cid, act, {edit: false})
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
- act = _post_action(env, para)
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, act, nil, nil)
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
- if act.is_a?(Integer)
743
- ent['action'] = act if act != 0
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
- _div_entry(env, ent),
753
- _div_index(env, idx)
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 _call_index_edit()
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
- if lnum != 0
823
- msg = 'This is a historical version of this Case'
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
- ].join('')
832
- return _resp_success(env, body)
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
- _div_list(env, resp, ListEntry),
916
- _div_page(resp){|qu, txt| _a_entry_search(env, qu, txt)},
917
- ].join('')
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
- # get the index
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
- _div_list(env, resp, ListEntry),
955
- _div_page(resp){|qu, txt| _a_entry_search(env, qu, txt)},
956
- ].join('')
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
- if it != 0
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
- when :log
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, _util_time(env, it))
1417
+ cd = _a_entry(env, cid, obj[:entry], 0, tme)
1338
1418
  when :log
1339
- cd = _a_log(env, cid, obj[:log], _util_time(env, it))
1419
+ cd = _a_log(env, cid, obj[:log], tme)
1340
1420
  else
1341
- cd = _util_time(env, it)
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
- cd ? (DivListItem % [cc, cd]) : ''
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">Tags</div>',
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">Stats</div>',
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">Files</div>',
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
- }, 'all open'),
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
- _util_time(env, ent['time']),
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
- time = _util_time(env, log['time'])
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
- _util_time(env, log['time']),
2339
+ ICFS.time_weekday(log['time'], env['icfs'].config),
2235
2340
  Rack::Utils.escape_html(log['user']),
2236
2341
  log['prev'],
2237
- _a_entry(env, cid, enum, lnum, log['entry']['hash']),
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>%s%s%s%s
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 << _a_entry_edit(env, cid, 0, anum, 'New Entry in Action')
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
- _util_time(env, tk['time']),
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 = _util_time(env, val)
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] ? _util_time(env, 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
- def _form_entry(env, cid, ent=nil)
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 = _util_time(env, ent['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
- (ent && ent['action']) ? ent['action'] : 0,
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, opt={})
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, _util_time(env, tk['time']) ]
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 = _util_time(env, tk['time'])
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 activitires.
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" class="%s">%s
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
- tz = env['icfs'].config.get('tz')
3689
- return FormConfig % [tz]
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