Merge branch 'ManuallyCreateLogs-#29' into Release0.2
This commit is contained in:
commit
a3c4212f0b
BIN
DataCenter_Windows/DBTestData/flexitimedb_12-Apr-2017.db
Normal file
BIN
DataCenter_Windows/DBTestData/flexitimedb_12-Apr-2017.db
Normal file
Binary file not shown.
@ -102,5 +102,9 @@ namespace Interfaces
|
|||||||
Group GetGroup(int groupId);
|
Group GetGroup(int groupId);
|
||||||
OperationResponse UpdateGroup(Group group);
|
OperationResponse UpdateGroup(Group group);
|
||||||
OperationResponse DeleteGroup(int groupId);
|
OperationResponse DeleteGroup(int groupId);
|
||||||
|
|
||||||
|
OperationResponse DeleteLog(TimeLog log);
|
||||||
|
OperationResponse CreateLog(TimeLog log);
|
||||||
|
OperationResponse UpdateLog(TimeLog log);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ namespace Interfaces
|
|||||||
public DateTimeOffset EventTime { get; set; }
|
public DateTimeOffset EventTime { get; set; }
|
||||||
public int CalendarWeek { get; set; }
|
public int CalendarWeek { get; set; }
|
||||||
public int Year { get; set; }
|
public int Year { get; set; }
|
||||||
|
public LogSource Source { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum LogDirection
|
public enum LogDirection
|
||||||
@ -19,4 +20,12 @@ namespace Interfaces
|
|||||||
IN = 1,
|
IN = 1,
|
||||||
OUT = 2
|
OUT = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum LogSource
|
||||||
|
{
|
||||||
|
UNKNOWN=0,
|
||||||
|
IDENTIFIER=1,
|
||||||
|
UI=2,
|
||||||
|
TRAYAPP=3
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
namespace SQLiteRepository
|
||||||
|
{
|
||||||
|
public enum LogSourceDb
|
||||||
|
{
|
||||||
|
UNKNOWN=0,
|
||||||
|
IDENTIFIER = 1,
|
||||||
|
UI = 2,
|
||||||
|
TRAYAPP = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -18,6 +18,14 @@ namespace SQLiteRepository
|
|||||||
"select * from " + nameof(UserIdentity) + " order by " + nameof(UserIdentity.LastName) + " collate nocase, " +
|
"select * from " + nameof(UserIdentity) + " order by " + nameof(UserIdentity.LastName) + " collate nocase, " +
|
||||||
nameof(UserIdentity.FirstName) + " collate nocase limit ? offset ?";
|
nameof(UserIdentity.FirstName) + " collate nocase limit ? offset ?";
|
||||||
|
|
||||||
|
public const string GET_ALL_USERS_BY_GROUP =
|
||||||
|
"select u." + nameof(UserIdentity.Id) + ", u." + nameof(UserIdentity.FirstName) + ", u." +
|
||||||
|
nameof(UserIdentity.LastName) + ", u." + nameof(UserIdentity.HoursPerWeek) + ", u." +
|
||||||
|
nameof(UserIdentity.IsContractor) + " from " + nameof(UserIdentity) + " u left join " +
|
||||||
|
nameof(UserGroupJoinDb) + " ugj on ugj." + nameof(UserGroupJoinDb.UserId_FK) + " = u." +
|
||||||
|
nameof(UserIdentity.Id) + " where ugj." + nameof(UserGroupJoinDb.GroupId_FK) + "=? order by u." +
|
||||||
|
nameof(UserIdentity.LastName) + " collate nocase, u." + nameof(UserIdentity.LastName) + " collate nocase";
|
||||||
|
|
||||||
public const string GET_USER_BY_ID =
|
public const string GET_USER_BY_ID =
|
||||||
"select * from " + nameof(UserIdentity) + " where " + nameof(UserIdentity.Id) + "=?";
|
"select * from " + nameof(UserIdentity) + " where " + nameof(UserIdentity.Id) + "=?";
|
||||||
|
|
||||||
@ -38,6 +46,11 @@ namespace SQLiteRepository
|
|||||||
"update " + nameof(CardUniqueId) + " set " + nameof(CardUniqueId.LastUsed) + " = ? where " +
|
"update " + nameof(CardUniqueId) + " set " + nameof(CardUniqueId.LastUsed) + " = ? where " +
|
||||||
nameof(CardUniqueId.Id) + " = ?";
|
nameof(CardUniqueId.Id) + " = ?";
|
||||||
|
|
||||||
|
public const string UPDATE_USER_DETAILS =
|
||||||
|
"update " + nameof(UserIdentity) + " set " + nameof(UserIdentity.FirstName) + "=?, " +
|
||||||
|
nameof(UserIdentity.LastName) + "=?, " + nameof(UserIdentity.HoursPerWeek) + "=?," +
|
||||||
|
nameof(UserIdentity.IsContractor) + "=? where " + nameof(UserIdentity.Id) + "=?";
|
||||||
|
|
||||||
public const string SEARCH_USER_LIST =
|
public const string SEARCH_USER_LIST =
|
||||||
"SELECT * FROM " + nameof(UserIdentity) + " where(" + nameof(UserIdentity.FirstName) + " Like ? OR " +
|
"SELECT * FROM " + nameof(UserIdentity) + " where(" + nameof(UserIdentity.FirstName) + " Like ? OR " +
|
||||||
nameof(UserIdentity.LastName) + " Like ?)";
|
nameof(UserIdentity.LastName) + " Like ?)";
|
||||||
|
|||||||
@ -50,7 +50,7 @@ namespace SQLiteRepository
|
|||||||
{
|
{
|
||||||
users =
|
users =
|
||||||
_connection.Query<UserIdentity>(
|
_connection.Query<UserIdentity>(
|
||||||
"select u.Id, u.FirstName, u.LastName, u.HoursPerWeek, u.IsContractor from UserIdentity u left join UserGroupJoinDb ugj on ugj.UserId_FK = u.Id where ugj.GroupId_FK=?",
|
SQLiteProcedures.GET_ALL_USERS_BY_GROUP,
|
||||||
groupId);
|
groupId);
|
||||||
userCount = users.Count;
|
userCount = users.Count;
|
||||||
}
|
}
|
||||||
@ -311,7 +311,7 @@ namespace SQLiteRepository
|
|||||||
{
|
{
|
||||||
//edit..
|
//edit..
|
||||||
_connection.Query<UserIdentity>(
|
_connection.Query<UserIdentity>(
|
||||||
"update UserIdentity set FirstName=?, LastName=?, HoursPerWeek=?,IsContractor=? where Id=?",
|
SQLiteProcedures.UPDATE_USER_DETAILS,
|
||||||
user.FirstName,
|
user.FirstName,
|
||||||
user.LastName,
|
user.LastName,
|
||||||
user.HoursPerWeek,
|
user.HoursPerWeek,
|
||||||
@ -423,7 +423,8 @@ namespace SQLiteRepository
|
|||||||
IdentifierId = ident.Id,
|
IdentifierId = ident.Id,
|
||||||
Direction = logDirection,
|
Direction = logDirection,
|
||||||
Year = year,
|
Year = year,
|
||||||
CalendarWeek = calendarWeek
|
CalendarWeek = calendarWeek,
|
||||||
|
Source = LogSourceDb.IDENTIFIER
|
||||||
};
|
};
|
||||||
|
|
||||||
_connection.Insert(timeLog);
|
_connection.Insert(timeLog);
|
||||||
@ -459,7 +460,6 @@ namespace SQLiteRepository
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var t = new UserGroupJoinDb();
|
|
||||||
query =
|
query =
|
||||||
_connection.Query<GroupDb>(
|
_connection.Query<GroupDb>(
|
||||||
"select gdb.GroupId, gdb.GroupName, gdb.AssignedUserCount" +
|
"select gdb.GroupId, gdb.GroupName, gdb.AssignedUserCount" +
|
||||||
@ -500,11 +500,6 @@ namespace SQLiteRepository
|
|||||||
public OperationResponse UpdateGroup(Group group)
|
public OperationResponse UpdateGroup(Group group)
|
||||||
{
|
{
|
||||||
//TODO: I would probably prefer to do this manually....
|
//TODO: I would probably prefer to do this manually....
|
||||||
var groupDb = new GroupDb
|
|
||||||
{
|
|
||||||
GroupId = group.Id,
|
|
||||||
GroupName = group.Name
|
|
||||||
};
|
|
||||||
var resp = _connection.Query<GroupDb>("update GroupDb set GroupName=? where GroupId=?", group.Name, group.Id);
|
var resp = _connection.Query<GroupDb>("update GroupDb set GroupName=? where GroupId=?", group.Name, group.Id);
|
||||||
//var resp = _connection.Update(groupDb);
|
//var resp = _connection.Update(groupDb);
|
||||||
return OperationResponse.UPDATED;
|
return OperationResponse.UPDATED;
|
||||||
@ -516,6 +511,73 @@ namespace SQLiteRepository
|
|||||||
return OperationResponse.DELETED;
|
return OperationResponse.DELETED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public OperationResponse DeleteLog(TimeLog log)
|
||||||
|
{
|
||||||
|
var query = _connection.Query<TimeLogDb>(
|
||||||
|
"select * from TimeLogDb where Id=?", log.Id);
|
||||||
|
|
||||||
|
if (!query.Any())
|
||||||
|
return OperationResponse.FAILED;
|
||||||
|
|
||||||
|
_connection.ExecuteScalar<TimeLogDb>("delete from TimeLogDb where Id=?", log.Id);
|
||||||
|
|
||||||
|
return OperationResponse.DELETED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OperationResponse CreateLog(TimeLog log)
|
||||||
|
{
|
||||||
|
var calendarWeek = GetIso8601CalendarWeek(log.EventTime.UtcDateTime);
|
||||||
|
var year = log.EventTime.Year;
|
||||||
|
var dbLog = new TimeLogDb
|
||||||
|
{
|
||||||
|
SwipeEventDateTime = log.EventTime,
|
||||||
|
Direction = (LogDirectionDb)(int)log.Direction,
|
||||||
|
Year = year,
|
||||||
|
CalendarWeek = calendarWeek,
|
||||||
|
Source = (LogSourceDb)(int)log.Source,
|
||||||
|
UserId_FK = log.UserId,
|
||||||
|
IdentifierId = ConvertSourceToIdentifierId(log.Source),
|
||||||
|
};
|
||||||
|
_connection.Insert(dbLog);
|
||||||
|
return OperationResponse.CREATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OperationResponse UpdateLog(TimeLog log)
|
||||||
|
{
|
||||||
|
var query = _connection.Query<TimeLogDb>(
|
||||||
|
"select * from TimeLogDb where Id=?", log.Id);
|
||||||
|
if(!query.Any())
|
||||||
|
return OperationResponse.FAILED;
|
||||||
|
|
||||||
|
if (log.CalendarWeek > 52 || log.CalendarWeek < 1)
|
||||||
|
{
|
||||||
|
log.CalendarWeek = GetIso8601CalendarWeek(log.EventTime.UtcDateTime);
|
||||||
|
}
|
||||||
|
if (log.Year < 2017)
|
||||||
|
{
|
||||||
|
log.Year = log.EventTime.Year;
|
||||||
|
}
|
||||||
|
_connection.ExecuteScalar<TimeLogDb>(
|
||||||
|
"update TimeLogDb set UserId_FK=?, Direction=?,SwipeEventDateTime=?,CalendarWeek=?,Year=?,Source=? where Id=?",
|
||||||
|
log.UserId, (LogDirectionDb) (int) log.Direction, log.EventTime, log.CalendarWeek, log.Year,
|
||||||
|
(LogSourceDb) (int) log.Source, log.Id);
|
||||||
|
|
||||||
|
return OperationResponse.UPDATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int ConvertSourceToIdentifierId(LogSource logSource)
|
||||||
|
{
|
||||||
|
switch (logSource)
|
||||||
|
{
|
||||||
|
case LogSource.UI:
|
||||||
|
return -100;
|
||||||
|
case LogSource.TRAYAPP:
|
||||||
|
return -200;
|
||||||
|
default:
|
||||||
|
return -10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private bool SetUserGroups(int userId, List<Group> groups)
|
private bool SetUserGroups(int userId, List<Group> groups)
|
||||||
{
|
{
|
||||||
var groupIds = GetGroupIds(groups.Select(x => x.Name).ToList());
|
var groupIds = GetGroupIds(groups.Select(x => x.Name).ToList());
|
||||||
@ -560,7 +622,7 @@ namespace SQLiteRepository
|
|||||||
EventTime = x.SwipeEventDateTime,
|
EventTime = x.SwipeEventDateTime,
|
||||||
UserId = x.UserId_FK,
|
UserId = x.UserId_FK,
|
||||||
Year = x.Year
|
Year = x.Year
|
||||||
}).ToList();
|
}).OrderBy(x=>x.EventTime.UtcDateTime).ToList();
|
||||||
|
|
||||||
var dict = new Dictionary<DayOfWeek, DailyLogs>();
|
var dict = new Dictionary<DayOfWeek, DailyLogs>();
|
||||||
var logList = new List<DailyLogs>();
|
var logList = new List<DailyLogs>();
|
||||||
@ -572,7 +634,7 @@ namespace SQLiteRepository
|
|||||||
}
|
}
|
||||||
|
|
||||||
//add the logs to the respective day of the week.
|
//add the logs to the respective day of the week.
|
||||||
foreach (var log in timeLogs)
|
foreach (var log in timeLogs.OrderBy(x=>x.EventTime))
|
||||||
{
|
{
|
||||||
dict[log.EventTime.DayOfWeek].Logs.Add(log);
|
dict[log.EventTime.DayOfWeek].Logs.Add(log);
|
||||||
}
|
}
|
||||||
@ -607,7 +669,7 @@ namespace SQLiteRepository
|
|||||||
private double CalculateDailyTotal(DailyLogs dailyLogs)
|
private double CalculateDailyTotal(DailyLogs dailyLogs)
|
||||||
{
|
{
|
||||||
var totalInTime = TimeSpan.FromSeconds(0);
|
var totalInTime = TimeSpan.FromSeconds(0);
|
||||||
var logs = dailyLogs.Logs.OrderBy(x => x.Id).ToArray();
|
var logs = dailyLogs.Logs.OrderBy(x => x.EventTime.UtcDateTime).ToArray();
|
||||||
var totalCalcMax = IsOdd(logs.Length) ? logs.Length - 1 : logs.Length;
|
var totalCalcMax = IsOdd(logs.Length) ? logs.Length - 1 : logs.Length;
|
||||||
for (int i = 0; i < totalCalcMax; i += 2)
|
for (int i = 0; i < totalCalcMax; i += 2)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -61,6 +61,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="CardUniqueId.cs" />
|
<Compile Include="CardUniqueId.cs" />
|
||||||
<Compile Include="GroupDb.cs" />
|
<Compile Include="GroupDb.cs" />
|
||||||
|
<Compile Include="LogSourceDb.cs" />
|
||||||
<Compile Include="SQLiteRepository.cs" />
|
<Compile Include="SQLiteRepository.cs" />
|
||||||
<Compile Include="Constants.cs" />
|
<Compile Include="Constants.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
|||||||
@ -13,5 +13,6 @@ namespace SQLiteRepository
|
|||||||
public DateTimeOffset SwipeEventDateTime { get; set; }
|
public DateTimeOffset SwipeEventDateTime { get; set; }
|
||||||
public int CalendarWeek { get; set; }
|
public int CalendarWeek { get; set; }
|
||||||
public int Year { get; set; }
|
public int Year { get; set; }
|
||||||
|
public LogSourceDb Source { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
using System;
|
||||||
|
using System.Web.Http;
|
||||||
|
using WindowsDataCenter.Helpers;
|
||||||
|
using Interfaces;
|
||||||
|
|
||||||
|
namespace WindowsDataCenter
|
||||||
|
{
|
||||||
|
[RoutePrefix("api/logs")]
|
||||||
|
public class LogsController:ApiController
|
||||||
|
{
|
||||||
|
private IRepository _repo;
|
||||||
|
private ILogger _logger;
|
||||||
|
|
||||||
|
public LogsController(IRepository repo, ILogger logger)
|
||||||
|
{
|
||||||
|
if (repo == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(repo));
|
||||||
|
}
|
||||||
|
if (logger == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(logger));
|
||||||
|
}
|
||||||
|
_repo = repo;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[Route("create")]
|
||||||
|
[CacheControl(MaxAge = 0)]
|
||||||
|
public IHttpActionResult CreateAndEditResultLog([FromBody] TimeLog log)
|
||||||
|
{
|
||||||
|
log.Source = LogSource.UI;
|
||||||
|
var resp = log.Id > 0 ? _repo.UpdateLog(log) : _repo.CreateLog(log);
|
||||||
|
return Ok(new {Id=log.Id, OperationResponse=resp});
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete]
|
||||||
|
[Route("delete")]
|
||||||
|
[CacheControl(MaxAge = 0)]
|
||||||
|
public IHttpActionResult DeleteLog([FromBody] TimeLog log)
|
||||||
|
{
|
||||||
|
_logger.Info("Removing Log {0} for user id {1}", log.Id, log.UserId);
|
||||||
|
_repo.DeleteLog(log);
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -44,16 +44,5 @@ namespace WindowsDataCenter
|
|||||||
Content = new StringContent(logId.ToString())
|
Content = new StringContent(logId.ToString())
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="log"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpPost]
|
|
||||||
[Route("manual")]
|
|
||||||
public IHttpActionResult ManuallyPostData([FromBody] ManualLog log)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -151,6 +151,7 @@
|
|||||||
<Compile Include="Controllers\CardsController.cs" />
|
<Compile Include="Controllers\CardsController.cs" />
|
||||||
<Compile Include="Configuration.cs" />
|
<Compile Include="Configuration.cs" />
|
||||||
<Compile Include="Controllers\GroupController.cs" />
|
<Compile Include="Controllers\GroupController.cs" />
|
||||||
|
<Compile Include="Controllers\LogsController.cs" />
|
||||||
<Compile Include="Controllers\TimelogController.cs" />
|
<Compile Include="Controllers\TimelogController.cs" />
|
||||||
<Compile Include="DefaultComponents\DefaultLogger.cs" />
|
<Compile Include="DefaultComponents\DefaultLogger.cs" />
|
||||||
<Compile Include="Helpers\CacheControlAttribute.cs" />
|
<Compile Include="Helpers\CacheControlAttribute.cs" />
|
||||||
@ -199,6 +200,9 @@
|
|||||||
<Content Include="www\css\bootstrap.min.css">
|
<Content Include="www\css\bootstrap.min.css">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Include="www\css\knockout.contextmenu.css">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="www\favicon.ico">
|
<Content Include="www\favicon.ico">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
@ -220,6 +224,9 @@
|
|||||||
<Content Include="www\js\bootstrap.min.js">
|
<Content Include="www\js\bootstrap.min.js">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Include="www\js\knockout.contextmenu.js">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="www\spa.css">
|
<Content Include="www\spa.css">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
/**
|
/**
|
||||||
* Create a request URL - references apiEndpoints object to construct url with args, and optional callback url.
|
* Create a request URL - references apiEndpoints object to construct url with args, and optional callback url.
|
||||||
* @param {string} routePath
|
* @param {string} routePath
|
||||||
* @param {Array<Object<string>} params - Key, Value object detailing the param name (key) and value (value).
|
* @param {Array<Object<string>>} params - Key, Value object detailing the param name (key) and value (value).
|
||||||
* @param {boolean} requiresCallback - True - add callback function for JSONP/CORS.
|
* @param {boolean} requiresCallback - True - add callback function for JSONP/CORS.
|
||||||
* @param {boolean} isAbsolutePath - True, create a relative URL (without root).
|
* @param {boolean} isAbsolutePath - True, create a relative URL (without root).
|
||||||
* @returns {string} the url generated
|
* @returns {string} the url generated
|
||||||
|
|||||||
@ -0,0 +1,59 @@
|
|||||||
|
/* knockout.contextmenu v1.0.0
|
||||||
|
Nicolás Escalante - nlante@gmail.com
|
||||||
|
Issues: https://github.com/nescalante/knockout.contextmenu/issues
|
||||||
|
License: MIT */
|
||||||
|
|
||||||
|
.context-menu {
|
||||||
|
position: absolute;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
z-index: 1030;
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
.context-menu ul {
|
||||||
|
line-height: 1.6;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
border: 1px solid #dddddd;
|
||||||
|
box-shadow: 4px 4px 8px rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
.context-menu ul > li {
|
||||||
|
padding: 4px 20px;
|
||||||
|
margin: 0;
|
||||||
|
z-index: 1031;
|
||||||
|
list-style-type: none;
|
||||||
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
.context-menu ul > li:hover {
|
||||||
|
background-color: #eeeeee;
|
||||||
|
}
|
||||||
|
.context-menu ul > li.disabled,
|
||||||
|
.context-menu ul > li.disabled a {
|
||||||
|
color: #666666;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
.context-menu ul > li.checked:before {
|
||||||
|
position: absolute;
|
||||||
|
content: "\2713";
|
||||||
|
left: 7px;
|
||||||
|
}
|
||||||
|
.context-menu ul > li.with-url {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.context-menu ul > li.with-url a {
|
||||||
|
display: block;
|
||||||
|
padding: 4px 20px;
|
||||||
|
text-decoration: none;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
.context-menu ul > li.separator {
|
||||||
|
margin: 4px 0;
|
||||||
|
padding: 0;
|
||||||
|
border-bottom: 1px solid #cccccc;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
.context-menu ul > li.separator:hover {
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
@ -4,16 +4,20 @@
|
|||||||
<title>Flexi Time Data Viewer</title>
|
<title>Flexi Time Data Viewer</title>
|
||||||
<link rel="shortcut icon" href="favicon.ico" />
|
<link rel="shortcut icon" href="favicon.ico" />
|
||||||
|
|
||||||
<link rel="stylesheet preload" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"/>
|
||||||
<link rel="stylesheet preload" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.6.1/css/bootstrap-datepicker3.min.css">
|
<!--<link rel="stylesheet preload" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.6.1/css/bootstrap-datepicker3.min.css"/>-->
|
||||||
<link href="spa.min.css" rel="stylesheet" />
|
<link href="spa.min.css" rel="stylesheet" />
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
|
<link href="css/knockout.contextmenu.css" rel="stylesheet" type="text/css"/>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.47/css/bootstrap-datetimepicker.min.css" />
|
||||||
|
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.0.0/knockout-min.js" type="text/javascript"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.0.0/knockout-min.js" type="text/javascript"></script>
|
||||||
|
<script src="js/knockout.contextmenu.js" type="text/javascript"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/sammy.js/0.7.6/sammy.js" type="text/javascript"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/sammy.js/0.7.6/sammy.js" type="text/javascript"></script>
|
||||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
|
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/momentjs/2.10.6/moment.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/momentjs/2.10.6/moment.min.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.6.1/js/bootstrap-datepicker.js"></script>
|
<!--<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.6.1/js/bootstrap-datepicker.js"></script>-->
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.47/js/bootstrap-datetimepicker.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body data-bind="css: {footerBody: errorData() !== null}">
|
<body data-bind="css: {footerBody: errorData() !== null}">
|
||||||
<nav class="navbar navbar-default">
|
<nav class="navbar navbar-default">
|
||||||
@ -246,9 +250,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
<!--<div class="row">
|
|
||||||
|
|
||||||
</div>-->
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-3 col-xs-12">
|
<div class="col-md-3 col-xs-12">
|
||||||
<div id="datePickerContainer">
|
<div id="datePickerContainer">
|
||||||
@ -259,7 +260,7 @@
|
|||||||
<!-- main content panel. -->
|
<!-- main content panel. -->
|
||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr data-bind="contextMenu: $root.createContextMenu">
|
||||||
<th>Day Of Week</th>
|
<th>Day Of Week</th>
|
||||||
<!-- ko foreach: new Array($root.getTimeLogEntryArrayLength(MaxDailyLogCount)) -->
|
<!-- ko foreach: new Array($root.getTimeLogEntryArrayLength(MaxDailyLogCount)) -->
|
||||||
<th>In</th>
|
<th>In</th>
|
||||||
@ -271,24 +272,30 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<!-- ko foreach: TimeLogs-->
|
<!-- ko foreach: TimeLogs-->
|
||||||
<tr>
|
<tr>
|
||||||
<td class="valign" data-bind="text: DayOfWeek"></td>
|
<td class="valign" data-bind="text: DayOfWeek, contextMenu: $root.createContextMenu"></td>
|
||||||
<!-- ko foreach: Logs -->
|
<!-- ko foreach: Logs -->
|
||||||
<td class="valign" data-bind="text: $root.convertToDisplayTime(EventTime)"></td>
|
<td class="valign" data-bind="text: $root.convertToDisplayTime(EventTime), contextMenu: $root.editContextMenu"></td>
|
||||||
<!-- /ko -->
|
<!-- /ko -->
|
||||||
<!-- ko foreach: new Array($root.correctLogOffset($parent.MaxDailyLogCount)-LogCount)-->
|
<!-- ko foreach: new Array($root.correctLogOffset($parent.MaxDailyLogCount)-LogCount)-->
|
||||||
<td class="valign"></td>
|
<td class="valign" data-bind="contextMenu: $root.createContextMenu"></td>
|
||||||
<!-- /ko -->
|
<!-- /ko -->
|
||||||
<td class="valign"data-bind="text: $root.convertToHours(DailyTotal)"></td>
|
<td class="valign" data-bind="text: $root.convertToHours(DailyTotal), contextMenu: $root.createContextMenu"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<!-- /ko -->
|
<!-- /ko -->
|
||||||
<tr>
|
<tr>
|
||||||
<td class="valign" data-bind="attr:{colspan: $root.correctLogOffset(MaxDailyLogCount)+1}">Weekly Total</td>
|
<td class="valign" data-bind="attr:{colspan: $root.correctLogOffset(MaxDailyLogCount)+1}, contextMenu: $root.createContextMenu">Weekly Total</td>
|
||||||
<td class="valign" for="dailyHrsTotal" data-bind="text: $root.convertToHours(WeeklyTotal)"></td>
|
<td class="valign" for="dailyHrsTotal" data-bind="text: $root.convertToHours(WeeklyTotal), contextMenu: $root.createContextMenu"></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!--<menu type="context" id="manualLogsMenu">
|
||||||
|
<menu label="ManuallyCreateLogs">
|
||||||
|
<menuitem label="Edit" onclick="$root.editLogClick()"/>
|
||||||
|
<menuitem label="Create" onlcick="$root.createLogClick()"/>
|
||||||
|
</menu>
|
||||||
|
</menu>-->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="aboutDialog" class="modal fade" role="dialog" data-bind="with: appDetails">
|
<div id="aboutDialog" class="modal fade" role="dialog" data-bind="with: appDetails">
|
||||||
@ -318,7 +325,41 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="manualLogDialog" class="modal fade" role="dialog" data-bind="with: manualLog">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||||
|
<h4>MANUAL EDIT</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body" style="height: 300px;">
|
||||||
|
<form action="#manualLog" method="post" class="form-group">
|
||||||
|
<input type="hidden" name="Id" data-bind="value: Id"/>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="input-group date" id="datetimepicker1">
|
||||||
|
<input type="text" class="form-control" />
|
||||||
|
<span class="input-group-addon">
|
||||||
|
<span class="glyphicon glyphicon-calendar"></span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="input-group">
|
||||||
|
<select data-bind="options: $root.possibleLogDirections,
|
||||||
|
optionsText: function(item) { return item.Text },
|
||||||
|
optionsValue: function(item){ return item.value },
|
||||||
|
value: Direction,
|
||||||
|
optionsCaption: 'Choose...'"></select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br/>
|
||||||
|
<button type="submit" class="btn btn-primary">Submit</button>
|
||||||
|
<button type="button" class="btn btn-secondary close" data-dismiss="modal">Cancel</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<footer data-bind="with: errorData, css: {footer: $root.errorData()!==null}">
|
<footer data-bind="with: errorData, css: {footer: $root.errorData()!==null}">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<!-- Alert/Error banner-->
|
<!-- Alert/Error banner-->
|
||||||
@ -332,7 +373,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
<script src="Helpers.js" type="text/javascript"></script>
|
||||||
<script src="spa.min.js" type="text/javascript"></script>
|
<script src="spa.js" type="text/javascript"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@ -0,0 +1,362 @@
|
|||||||
|
/* knockout.contextmenu v1.0.0
|
||||||
|
Nicolás Escalante - nlante@gmail.com
|
||||||
|
Issues: https://github.com/nescalante/knockout.contextmenu/issues
|
||||||
|
License: MIT */
|
||||||
|
|
||||||
|
(function (undefined) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// client
|
||||||
|
if (typeof ko !== undefined + "") {
|
||||||
|
bindContextMenu(ko);
|
||||||
|
}
|
||||||
|
|
||||||
|
// node
|
||||||
|
if (typeof module !== undefined + "" && module.exports && typeof require !== undefined + "") {
|
||||||
|
bindContextMenu(require("knockout"));
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindContextMenu(ko) {
|
||||||
|
var currentMenu;
|
||||||
|
var elementMapping = [];
|
||||||
|
var utils = ko.utils;
|
||||||
|
var registerEvent = utils.registerEventHandler;
|
||||||
|
var isObservable = ko.isObservable;
|
||||||
|
|
||||||
|
registerEvent(document, "click", function (event) {
|
||||||
|
var button = event.which || event.button;
|
||||||
|
if (!event.defaultPrevented && button < 2) {
|
||||||
|
hideCurrentMenu();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
utils.contextMenu = {
|
||||||
|
getMenuFor: function (element, event) {
|
||||||
|
var result = getMapping(element);
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
return result.get(event);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
openMenuFor: function (element, event) {
|
||||||
|
var result = getMapping(element);
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
return result.open(event);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.bindingHandlers.contextMenu = {
|
||||||
|
init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
|
||||||
|
var eventsToHandle = valueAccessor() || {};
|
||||||
|
var allBindings = allBindingsAccessor();
|
||||||
|
var defaultClass = allBindings.contextMenuClass || "context-menu";
|
||||||
|
var activeElement;
|
||||||
|
|
||||||
|
// bind on click? bind on context click?
|
||||||
|
if (allBindings.bindMenuOnClick) {
|
||||||
|
registerEvent(element, "click", openMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allBindings.bindMenuOnContextMenu === undefined || allBindings.bindMenuOnContextMenu) {
|
||||||
|
registerEvent(element, "contextmenu", openMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
elementMapping.push({
|
||||||
|
element: element,
|
||||||
|
get: function () {
|
||||||
|
return activeElement;
|
||||||
|
},
|
||||||
|
|
||||||
|
open: openMenu,
|
||||||
|
hide: function () {
|
||||||
|
if (activeElement) {
|
||||||
|
activeElement.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function mouseX(evt) {
|
||||||
|
if (evt.pageX) {
|
||||||
|
return evt.pageX;
|
||||||
|
} else if (evt.clientX) {
|
||||||
|
return evt.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouseY(evt) {
|
||||||
|
if (evt.pageY) {
|
||||||
|
return evt.pageY;
|
||||||
|
} else if (evt.clientY) {
|
||||||
|
return evt.clientY + (document.documentElement.scrollTop || document.body.scrollTop);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function openMenu(event) {
|
||||||
|
activeElement = getMenu(event);
|
||||||
|
var menuElement = activeElement.element;
|
||||||
|
|
||||||
|
hideCurrentMenu();
|
||||||
|
|
||||||
|
if (menuElement) {
|
||||||
|
// make visibility hidden, then add to DOM so that we can get the height/width of the menu
|
||||||
|
menuElement.style.visibility = "hidden";
|
||||||
|
(document.body || document).appendChild(menuElement);
|
||||||
|
|
||||||
|
// set location
|
||||||
|
if (event) {
|
||||||
|
var bottomOfViewport = window.innerHeight + window.pageYOffset;
|
||||||
|
var rightOfViewport = window.innerWidth + window.pageXOffset;
|
||||||
|
|
||||||
|
if (mouseY(event) + menuElement.offsetHeight > bottomOfViewport) {
|
||||||
|
menuElement.style.top = 1 * (bottomOfViewport - menuElement.offsetHeight - 10) + "px";
|
||||||
|
} else {
|
||||||
|
menuElement.style.top = mouseY(event) + "px";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mouseX(event) + menuElement.offsetWidth > rightOfViewport) {
|
||||||
|
menuElement.style.left = 1 * (rightOfViewport - menuElement.offsetWidth - 10) + "px";
|
||||||
|
} else {
|
||||||
|
menuElement.style.left = mouseX(event) + "px";
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
} else {
|
||||||
|
menuElement.style.top = (element.offsetTop + element.offsetHeight) + "px";
|
||||||
|
menuElement.style.left = (element.offsetLeft + element.offsetWidth) + "px";
|
||||||
|
}
|
||||||
|
|
||||||
|
// now set to visible
|
||||||
|
menuElement.style.visibility = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// replace current menu with the recently created
|
||||||
|
currentMenu = menuElement;
|
||||||
|
|
||||||
|
return activeElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMenu(event) {
|
||||||
|
var menu;
|
||||||
|
var hasChecks = false;
|
||||||
|
var elements = [];
|
||||||
|
var actions = [];
|
||||||
|
var items = [];
|
||||||
|
var props = Object.keys(
|
||||||
|
ko.isObservable(eventsToHandle) ?
|
||||||
|
eventsToHandle() :
|
||||||
|
eventsToHandle
|
||||||
|
);
|
||||||
|
|
||||||
|
props.forEach(function (eventNameOutsideClosure) {
|
||||||
|
pushItem(eventNameOutsideClosure);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (elements.length) {
|
||||||
|
menu = document.createElement("div");
|
||||||
|
menu.className = defaultClass;
|
||||||
|
|
||||||
|
// you may need padding to menus that has checks
|
||||||
|
menu.innerHTML = "<ul class=\"" + (hasChecks ? "has-checks" : "") + '">' +
|
||||||
|
elements.join("") +
|
||||||
|
"</ul>";
|
||||||
|
|
||||||
|
// map items to actions
|
||||||
|
elements.forEach(function (item, index) {
|
||||||
|
registerEvent(menu.children[0].children[index], "click", function (event) {
|
||||||
|
var result = actions[index](viewModel, event);
|
||||||
|
|
||||||
|
if (!result && event) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
element: menu,
|
||||||
|
items: items,
|
||||||
|
open: openMenu,
|
||||||
|
hide: function () {
|
||||||
|
if (menu && menu.parentNode) {
|
||||||
|
menu.parentNode.removeChild(menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentMenu = null;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function pushItem(eventName) {
|
||||||
|
var item = getMenuProperties(eventName);
|
||||||
|
var classes = [];
|
||||||
|
var id = "";
|
||||||
|
var liHtml;
|
||||||
|
|
||||||
|
if (item.isVisible) {
|
||||||
|
hasChecks = hasChecks || item.isBoolean;
|
||||||
|
|
||||||
|
if (item.id) {
|
||||||
|
id = item.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set css classes
|
||||||
|
if (item.isChecked) {
|
||||||
|
classes.push("checked");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.isDisabled) {
|
||||||
|
classes.push("disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.isSeparator) {
|
||||||
|
classes.push("separator");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.url) {
|
||||||
|
classes.push("with-url");
|
||||||
|
}
|
||||||
|
|
||||||
|
liHtml = "<li " + (id ? ('id="' + id + '" ') : "") +
|
||||||
|
' class="' + classes.join(" ") + '">' +
|
||||||
|
item.html +
|
||||||
|
"</li>";
|
||||||
|
|
||||||
|
elements.push(liHtml);
|
||||||
|
actions.push(item.action);
|
||||||
|
}
|
||||||
|
|
||||||
|
items.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMenuProperties(eventName) {
|
||||||
|
var text = "";
|
||||||
|
var html = "";
|
||||||
|
var currentEvent = ko.isObservable(eventsToHandle) ?
|
||||||
|
eventsToHandle()[eventName] :
|
||||||
|
eventsToHandle[eventName];
|
||||||
|
var item = currentEvent || {};
|
||||||
|
var id = item.id;
|
||||||
|
var url = (isObservable(item.url) ? item.url() : item.url);
|
||||||
|
var isVisible = item.visible === undefined || item.visible === null ||
|
||||||
|
(isObservable(item.visible) && item.visible()) ||
|
||||||
|
(!isObservable(item.visible) && !!item.visible);
|
||||||
|
var isChecked = false;
|
||||||
|
var isEnabled = !item.disabled ||
|
||||||
|
(isObservable(item.disabled) && !item.disabled()) ||
|
||||||
|
(isObservable(item.enabled) && item.enabled()) ||
|
||||||
|
(!isObservable(item.enabled) && !!item.enabled);
|
||||||
|
var isBoolean = false;
|
||||||
|
var isDisabled = !isEnabled;
|
||||||
|
var isSeparator = !!currentEvent.separator;
|
||||||
|
|
||||||
|
if (!isSeparator) {
|
||||||
|
text = isObservable(item.text) ? item.text() : item.text;
|
||||||
|
|
||||||
|
if (!text) {
|
||||||
|
text = eventName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (url) {
|
||||||
|
html = '<a href="' + url + '">' + text + "</a>";
|
||||||
|
} else {
|
||||||
|
html = text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((isObservable(item) && typeof item() === "boolean") ||
|
||||||
|
(isObservable(item.action) && typeof item.action() === "boolean")) {
|
||||||
|
isBoolean = true;
|
||||||
|
|
||||||
|
if ((item.action && item.action()) ||
|
||||||
|
(typeof item === "function" && item())) {
|
||||||
|
isChecked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
html: html,
|
||||||
|
text: text,
|
||||||
|
url: url,
|
||||||
|
id: id,
|
||||||
|
isVisible: isVisible,
|
||||||
|
isChecked: isChecked,
|
||||||
|
isEnabled: isEnabled,
|
||||||
|
isDisabled: isDisabled,
|
||||||
|
isBoolean: isBoolean,
|
||||||
|
isSeparator: isSeparator,
|
||||||
|
action: action
|
||||||
|
};
|
||||||
|
|
||||||
|
function action(viewModel, event) {
|
||||||
|
var error = eventName + " option must have an action or an url.";
|
||||||
|
|
||||||
|
if (isDisabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if option is a boolean
|
||||||
|
if (isObservable(item) && typeof item() === "boolean") {
|
||||||
|
item(!item());
|
||||||
|
}
|
||||||
|
|
||||||
|
// is an object? well, lets check it properties
|
||||||
|
else if (typeof item === "object") {
|
||||||
|
// check if has an action or if its a separator
|
||||||
|
if (!item.action && !url && !isSeparator) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// evaluate action
|
||||||
|
else if (item.action) {
|
||||||
|
if (isObservable(item.action) && typeof item.action() === "boolean") {
|
||||||
|
item.action(!item.action());
|
||||||
|
} else {
|
||||||
|
item.action(viewModel, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// its not an observable, should be a function
|
||||||
|
else if (typeof item === "function") {
|
||||||
|
item(viewModel, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
// nothing to do with this
|
||||||
|
else {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function hideCurrentMenu() {
|
||||||
|
if (currentMenu && currentMenu.parentNode) {
|
||||||
|
currentMenu.parentNode.removeChild(currentMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentMenu = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMapping(element) {
|
||||||
|
var i = 0;
|
||||||
|
|
||||||
|
for (; i < elementMapping.length; i++) {
|
||||||
|
if (elementMapping[i].element === element) {
|
||||||
|
return elementMapping[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
@ -12,7 +12,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.bootstrap-datetimepicker-widget tr:hover {
|
.bootstrap-datetimepicker-widget tr:hover {
|
||||||
background-color: #808080;
|
background-color: #a9a9a9;
|
||||||
}
|
}
|
||||||
.datepicker tr.highlight {
|
.datepicker tr.highlight {
|
||||||
background: #eeeeee;
|
background: #eeeeee;
|
||||||
|
|||||||
@ -1,7 +1,12 @@
|
|||||||
function DataVM() {
|
function DataVM() {
|
||||||
"use strict";
|
"use strict";
|
||||||
var self = this;
|
var self = this;
|
||||||
|
self.helpers = new Helpers();
|
||||||
self.menuOptions = ["Home"];
|
self.menuOptions = ["Home"];
|
||||||
|
self.possibleLogDirections = ko.observableArray([
|
||||||
|
{ Text: "In", value: 1 },
|
||||||
|
{ Text: "Out", value: 2 }
|
||||||
|
]),
|
||||||
self.chosenMenuItemId = ko.observable();
|
self.chosenMenuItemId = ko.observable();
|
||||||
self.appDetails = ko.observable(null);
|
self.appDetails = ko.observable(null);
|
||||||
self.userList = ko.observable(null);
|
self.userList = ko.observable(null);
|
||||||
@ -10,8 +15,10 @@
|
|||||||
self.userTimeLogData = ko.observable(null);
|
self.userTimeLogData = ko.observable(null);
|
||||||
self.unassignedCardData = ko.observable(null);
|
self.unassignedCardData = ko.observable(null);
|
||||||
self.chosenTimeLogUserId = -1;
|
self.chosenTimeLogUserId = -1;
|
||||||
|
self.selectedTimeLogDate = ko.observable(null);
|
||||||
self.selectedCalendarWeek = ko.observable(0);
|
self.selectedCalendarWeek = ko.observable(0);
|
||||||
self.errorData = ko.observable(null);
|
self.errorData = ko.observable(null);
|
||||||
|
self.manualLog = ko.observable(null);
|
||||||
self.apiEndpoints = {
|
self.apiEndpoints = {
|
||||||
root: "http://localhost:8800",
|
root: "http://localhost:8800",
|
||||||
getUserList: "/api/users",
|
getUserList: "/api/users",
|
||||||
@ -20,7 +27,9 @@
|
|||||||
getTimeLogs: "/api/timelogs",
|
getTimeLogs: "/api/timelogs",
|
||||||
getUnassignedCards: "/api/cards/unassigned",
|
getUnassignedCards: "/api/cards/unassigned",
|
||||||
getGroups: "/api/groups",
|
getGroups: "/api/groups",
|
||||||
getAppDetails: "/api/app"
|
getAppDetails: "/api/app",
|
||||||
|
manualLogsCreate: "/api/logs/create",
|
||||||
|
manualLogsDelete: "/api/logs/delete"
|
||||||
};
|
};
|
||||||
self.uiPages = {
|
self.uiPages = {
|
||||||
users: "users",
|
users: "users",
|
||||||
@ -39,7 +48,7 @@
|
|||||||
}
|
}
|
||||||
var url = "timelogs" + "/" + userId;
|
var url = "timelogs" + "/" + userId;
|
||||||
if (args) {
|
if (args) {
|
||||||
url = self.createRequestUrl(url, args, false, false);
|
url = self.helpers.createRequestUrl(url, args, false, false);
|
||||||
}
|
}
|
||||||
location.hash = url;
|
location.hash = url;
|
||||||
};
|
};
|
||||||
@ -52,86 +61,11 @@
|
|||||||
};
|
};
|
||||||
self.errorData(errDat);
|
self.errorData(errDat);
|
||||||
}
|
}
|
||||||
self.processRequestFailure = function (xmlHttpRequest, textStatus, errorThrown) {
|
|
||||||
if (xmlHttpRequest.readyState === 4) {
|
|
||||||
return {
|
|
||||||
errorCode: xmlHttpRequest.status,
|
|
||||||
errorMessage: xmlHttpRequest.statusText,
|
|
||||||
errorSource: ""
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else if (xmlHttpRequest.readyState === 0) {
|
|
||||||
return {
|
|
||||||
errorCode: xmlHttpRequest.status,
|
|
||||||
errorMessage: "Network Error - Is the server available?",
|
|
||||||
errorSource: ""
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return {
|
|
||||||
errorCode: xmlHttpRequest.status,
|
|
||||||
errorMessage: "Unknown Error",
|
|
||||||
errorSource: ""
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* Create a request URL - references apiEndpoints object to construct url with args, and optional callback url.
|
|
||||||
* @param {string} routePath
|
|
||||||
* @param {Array<Object<string>} params - Key, Value object detailing the param name (key) and value (value).
|
|
||||||
* @param {boolean} requiresCallback - True - add callback function for JSONP/CORS.
|
|
||||||
* @param {boolean} isAbsolutePath - True, create a relative URL (without root).
|
|
||||||
* @returns {string} the url generated
|
|
||||||
* @example
|
|
||||||
* createRequestUrl("/api/endpoint", [{key:"param", value:"value"}], true, false);
|
|
||||||
* returns: "http://192.168.2.2/api/endpoint?param=value&callback=?"
|
|
||||||
*/
|
|
||||||
self.createRequestUrl = function (routePath, params, requiresCallback, isAbsoluteUrl) {
|
|
||||||
var appender = "?";
|
|
||||||
var url = "";
|
|
||||||
if (isAbsoluteUrl) {
|
|
||||||
url = self.apiEndpoints.root;
|
|
||||||
}
|
|
||||||
url = url + routePath;
|
|
||||||
if (params !== undefined
|
|
||||||
&& params !== null) {
|
|
||||||
if (params.length > 0) {
|
|
||||||
for (var i = 0; i < params.length; i++) {
|
|
||||||
url += appender + params[i].key + "=" + params[i].value;
|
|
||||||
appender = "&";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (requiresCallback) {
|
|
||||||
url += appender + "callback=?";
|
|
||||||
}
|
|
||||||
return url;
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* Function to redirect to a page in the sammy.js eco system.
|
|
||||||
* Relies on "pagedestination" tag in the html. This is a button click handler.
|
|
||||||
* @param {Object<unknown>} data - dunno?
|
|
||||||
* @param {Object<buttonhandle>} event - handle to the button that was clicked.
|
|
||||||
* @returns {nothing} - redirects to the url referenced by the pageDestination tag.
|
|
||||||
*/
|
|
||||||
self.returnButtonClick = function (data, event) {
|
self.returnButtonClick = function (data, event) {
|
||||||
var target = null;
|
var destination = self.helpers.getPageDestination(data, event);
|
||||||
if (event.target) target = event.target;
|
|
||||||
else if (event.srcElement) target = event.srcElement;
|
|
||||||
var destination = "";
|
|
||||||
if (target != null) {
|
|
||||||
for (var i = 0; i < target.attributes.length; i++) {
|
|
||||||
if (target.attributes[i].nodeName === "pagedestination") {
|
|
||||||
destination = target.attributes[i].value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (destination !== "") {
|
if (destination !== "") {
|
||||||
self.goToMenuOption(destination); //redirect to whereever the button is telling us to go..
|
self.goToMenuOption(destination); //redirect to whereever the button is telling us to go..
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
console.log("target is null, going nowhere");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
self.convertToHours = function (value) {
|
self.convertToHours = function (value) {
|
||||||
var hrs = value / 60;
|
var hrs = value / 60;
|
||||||
@ -151,16 +85,16 @@
|
|||||||
logCount += 1;
|
logCount += 1;
|
||||||
}
|
}
|
||||||
return logCount;
|
return logCount;
|
||||||
}
|
};
|
||||||
self.round = function(value, decimals) {
|
self.round = function(value, decimals) {
|
||||||
return parseFloat(Math.round(value * 100) / 100).toFixed(decimals);
|
return parseFloat(Math.round(value * 100) / 100).toFixed(decimals);
|
||||||
}
|
};
|
||||||
self.getTimeLogEntryArrayLength = function(maxDailyLogs) {
|
self.getTimeLogEntryArrayLength = function(maxDailyLogs) {
|
||||||
return Math.round(maxDailyLogs/2);
|
return Math.round(maxDailyLogs/2);
|
||||||
};
|
};
|
||||||
self.padNumber = function(number) {
|
self.padNumber = function(number) {
|
||||||
return (number < 10 ? '0' : '') + number;
|
return (number < 10 ? "0" : "") + number;
|
||||||
}
|
};
|
||||||
self.convertToDisplayDateTime = function (dateValue) {
|
self.convertToDisplayDateTime = function (dateValue) {
|
||||||
var date = new Date(dateValue); // dd MM YY HH:mm:ss e.g.: 01 Mar 17 17:34:02
|
var date = new Date(dateValue); // dd MM YY HH:mm:ss e.g.: 01 Mar 17 17:34:02
|
||||||
return date.getDate() + " "
|
return date.getDate() + " "
|
||||||
@ -215,7 +149,7 @@
|
|||||||
value: data
|
value: data
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
var url = self.createRequestUrl("users", args, false, false);
|
var url = self.helpers.createRequestUrl("users", args, false, false);
|
||||||
location.hash = url;
|
location.hash = url;
|
||||||
console.log(url);
|
console.log(url);
|
||||||
};
|
};
|
||||||
@ -230,38 +164,53 @@
|
|||||||
value: pageNumber
|
value: pageNumber
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
var url = self.createRequestUrl("users", args, false, false);
|
var url = self.helpers.createRequestUrl("users", args, false, false);
|
||||||
location.hash = url;
|
location.hash = url;
|
||||||
console.log(url);
|
console.log(url);
|
||||||
};
|
};
|
||||||
self.initDatePicker = function (selectedDate) {
|
self.initDatePicker = function (selectedDate) {
|
||||||
$("#weeklyDatePicker").datepicker({
|
|
||||||
weekStart: 1,
|
|
||||||
maxViewMode: 2,
|
|
||||||
endDate: "+0d",
|
|
||||||
todayBtn: "linked",
|
|
||||||
format: "yyyy-mm-dd",
|
|
||||||
todayHighlight: true,
|
|
||||||
calendarWeeks: true
|
|
||||||
});
|
|
||||||
if (!selectedDate) {
|
if (!selectedDate) {
|
||||||
selectedDate = new Date();
|
selectedDate = new Date();
|
||||||
} else {
|
} else {
|
||||||
selectedDate = new Date(selectedDate);
|
selectedDate = new Date(selectedDate);
|
||||||
}
|
}
|
||||||
$("#weeklyDatePicker").datepicker("setDate", selectedDate);
|
moment.locale("en", { week: { dow: 1 } });
|
||||||
|
$("#weeklyDatePicker").datetimepicker({
|
||||||
|
format: "DD/MM/YYYY",
|
||||||
|
inline: true,
|
||||||
|
showTodayButton: true,
|
||||||
|
calendarWeeks: true,
|
||||||
|
maxDate: "now",
|
||||||
|
date: selectedDate
|
||||||
|
});
|
||||||
};
|
};
|
||||||
self.assignHandler = function() {
|
self.assignHandler = function() {
|
||||||
var elem = $("#weeklyDatePicker")[0];
|
var elem = $("#weeklyDatePicker")[0];
|
||||||
var data = jQuery.hasData(elem) && jQuery._data(elem);
|
var data = jQuery.hasData(elem) && jQuery._data(elem);
|
||||||
if (!data.events.changeDate) {
|
if (!data.events) {
|
||||||
$("#weeklyDatePicker").on("changeDate", function (e) {
|
$("#weeklyDatePicker")
|
||||||
var kk = e.date;
|
.on("dp.change",
|
||||||
self.selectedCalendarWeek(moment(kk).isoWeek());
|
function(e) {
|
||||||
self.goToTimeLogs(self.chosenTimeLogUserId, null, [{ key: "selectedDate", value: moment(kk).format("MM-DD-YYYY") }]);
|
var value = e.date;
|
||||||
|
self.selectedCalendarWeek(moment(value).isoWeek());
|
||||||
|
self.goToTimeLogs(self.chosenTimeLogUserId,
|
||||||
|
null,
|
||||||
|
[{ key: "selectedDate", value: moment(value).format("MM-DD-YYYY") }]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
self.assignUpdateHandler = function() {
|
||||||
|
var elem = $("#datetimepicker1")[0];
|
||||||
|
var data = jQuery.hasData(elem) && jQuery._data(elem);
|
||||||
|
if (!data.events) {
|
||||||
|
$("#datetimepicker1")
|
||||||
|
.on("dp.change",
|
||||||
|
function(e) {
|
||||||
|
var value = e.date.toISOString();
|
||||||
|
self.manualLog().EventTime = value;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
};
|
||||||
self.getUserList = function (pageSize, pageNumber, groupId) {
|
self.getUserList = function (pageSize, pageNumber, groupId) {
|
||||||
var args = null;
|
var args = null;
|
||||||
if (pageSize && pageNumber) {
|
if (pageSize && pageNumber) {
|
||||||
@ -282,52 +231,52 @@
|
|||||||
value: groupId
|
value: groupId
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
var url = self.createRequestUrl(self.apiEndpoints.getUserList, args, false);
|
var url = self.helpers.createRequestUrl(self.apiEndpoints.getUserList, args, false);
|
||||||
$.getJSON(url, function (res) {
|
$.getJSON(url, function (res) {
|
||||||
self.userList(res);
|
self.userList(res);
|
||||||
$('[data-toggle="tooltip"]').tooltip();
|
$('[data-toggle="tooltip"]').tooltip();
|
||||||
}).fail(function (response, status, error) {
|
}).fail(function (response, status, error) {
|
||||||
console.log("error - getusers");
|
console.log("error - getusers");
|
||||||
var errObj = self.processRequestFailure(response, status, error);
|
var errObj = self.helpers.processRequestFailure(response, status, error);
|
||||||
self.assignErrorObject(errObj.errorCode, errObj.errorMessage, "getUserList");
|
self.assignErrorObject(errObj.errorCode, errObj.errorMessage, "getUserList");
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
self.getAppDetails = function() {
|
self.getAppDetails = function() {
|
||||||
var url = self.createRequestUrl(self.apiEndpoints.getAppDetails, null, false, false);
|
var url = self.helpers.createRequestUrl(self.apiEndpoints.getAppDetails, null, false, false);
|
||||||
$.getJSON(url, function (res) {
|
$.getJSON(url, function (res) {
|
||||||
self.appDetails(res);
|
self.appDetails(res);
|
||||||
}).fail(function (response, status, error) {
|
}).fail(function (response, status, error) {
|
||||||
console.log("error - getusers");
|
console.log("error - getusers");
|
||||||
var errObj = self.processRequestFailure(response, status, error);
|
var errObj = self.helpers.processRequestFailure(response, status, error);
|
||||||
self.assignErrorObject(errObj.errorCode, errObj.errorMessage, "getUserList");
|
self.assignErrorObject(errObj.errorCode, errObj.errorMessage, "getUserList");
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
self.searchUsers = function(query) {
|
self.searchUsers = function(query) {
|
||||||
var url = self.createRequestUrl(self.apiEndpoints.getUserList,
|
var url = self.helpers.createRequestUrl(self.apiEndpoints.getUserList,
|
||||||
[{ key: "query", value: query }], false, false);
|
[{ key: "query", value: query }], false, false);
|
||||||
$.getJSON(url,
|
$.getJSON(url,
|
||||||
function(res) {
|
function(res) {
|
||||||
self.userList(res);
|
self.userList(res);
|
||||||
}).fail(function(resp, status, error) {
|
}).fail(function(resp, status, error) {
|
||||||
self.goToMenuOption(self.uiPages.home());
|
self.goToMenuOption(self.uiPages.home());
|
||||||
var errObj = self.processRequestFailure(resp, status, error);
|
var errObj = self.helpers.processRequestFailure(resp, status, error);
|
||||||
self.assignErrorObject(errObj.errorCode, errObj.errorMessage, "searchUsers");
|
self.assignErrorObject(errObj.errorCode, errObj.errorMessage, "searchUsers");
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
self.getUserDetails = function (userId) {
|
self.getUserDetails = function (userId) {
|
||||||
var url = self.createRequestUrl(self.apiEndpoints.getUserDetails + "/" + userId, null, false);
|
var url = self.helpers.createRequestUrl(self.apiEndpoints.getUserDetails + "/" + userId, null, false);
|
||||||
$.getJSON(url, function (res) {
|
$.getJSON(url, function (res) {
|
||||||
self.chosenUserDetails(res);
|
self.chosenUserDetails(res);
|
||||||
}).fail(function (resp, status, error) {
|
}).fail(function (resp, status, error) {
|
||||||
console.log("error - getuserdetails");
|
console.log("error - getuserdetails");
|
||||||
var errObj = self.processRequestFailure(resp, status, error);
|
var errObj = self.helpers.processRequestFailure(resp, status, error);
|
||||||
self.assignErrorObject(errObj.errorCode, errObj.errorMessage, "getUserDetails");
|
self.assignErrorObject(errObj.errorCode, errObj.errorMessage, "getUserDetails");
|
||||||
self.goToMenuOption(self.uiPages.home());
|
self.goToMenuOption(self.uiPages.home());
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
self.submitChangedUser = function (user) {
|
self.submitChangedUser = function (user) {
|
||||||
var url = self.apiEndpoints.editUser;
|
var url = self.helpers.createRequestUrl(self.apiEndpoints.editUser, null, false, false);
|
||||||
$.post(url, user, function () {
|
$.post(url, user, function () {
|
||||||
}, "json")
|
}, "json")
|
||||||
.done(function () {
|
.done(function () {
|
||||||
@ -335,7 +284,7 @@
|
|||||||
self.goToMenuOption(self.uiPages.home());
|
self.goToMenuOption(self.uiPages.home());
|
||||||
})
|
})
|
||||||
.fail(function (resp, status, error) {
|
.fail(function (resp, status, error) {
|
||||||
var errObj = self.processRequestFailure(resp, status, error);
|
var errObj = self.helpers.processRequestFailure(resp, status, error);
|
||||||
self.assignErrorObject(errObj.errorCode, errObj.errorMessage, "submitChangedUser");
|
self.assignErrorObject(errObj.errorCode, errObj.errorMessage, "submitChangedUser");
|
||||||
self.chosenUserDetails(null);
|
self.chosenUserDetails(null);
|
||||||
self.goToMenuOption(self.uiPages.home());
|
self.goToMenuOption(self.uiPages.home());
|
||||||
@ -346,7 +295,7 @@
|
|||||||
if (selectedDate) {
|
if (selectedDate) {
|
||||||
urlArgs.push({ key: "selectedDate", value: selectedDate });
|
urlArgs.push({ key: "selectedDate", value: selectedDate });
|
||||||
}
|
}
|
||||||
var url = self.createRequestUrl(self.apiEndpoints.getTimeLogs,
|
var url = self.helpers.createRequestUrl(self.apiEndpoints.getTimeLogs,
|
||||||
urlArgs,
|
urlArgs,
|
||||||
false);
|
false);
|
||||||
$.getJSON(url, function (res) {
|
$.getJSON(url, function (res) {
|
||||||
@ -355,33 +304,103 @@
|
|||||||
self.assignHandler();
|
self.assignHandler();
|
||||||
}).fail(function (resp, status, error) {
|
}).fail(function (resp, status, error) {
|
||||||
console.log("error - getuserdetails");
|
console.log("error - getuserdetails");
|
||||||
var errObj = self.processRequestFailure(resp, status, error);
|
var errObj = self.helpers.processRequestFailure(resp, status, error);
|
||||||
self.assignErrorObject(errObj.errorCode, errObj.errorMessage, "getTimeLogData");
|
self.assignErrorObject(errObj.errorCode, errObj.errorMessage, "getTimeLogData");
|
||||||
self.goToMenuOption(self.uiPages.home()); //go home.
|
self.goToMenuOption(self.uiPages.home()); //go home.
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
self.getUnassignedCardData = function () {
|
self.getUnassignedCardData = function () {
|
||||||
var url = self.createRequestUrl(self.apiEndpoints.getUnassignedCards, null, false);
|
var url = self.helpers.createRequestUrl(self.apiEndpoints.getUnassignedCards, null, false);
|
||||||
$.getJSON(url, function (res) {
|
$.getJSON(url, function (res) {
|
||||||
self.unassignedCardData(res);
|
self.unassignedCardData(res);
|
||||||
}).fail(function (resp, status, error) {
|
}).fail(function (resp, status, error) {
|
||||||
console.log("error - getuserdetails");
|
console.log("error - getuserdetails");
|
||||||
var errObj = self.processRequestFailure(resp, status, error);
|
var errObj = self.helpers.processRequestFailure(resp, status, error);
|
||||||
self.assignErrorObject(errObj.errorCode, errObj.errorMessage, "getUnassignedCardData");
|
self.assignErrorObject(errObj.errorCode, errObj.errorMessage, "getUnassignedCardData");
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
self.getGroups = function (successFunc) {
|
self.getGroups = function (successFunc) {
|
||||||
var url = self.createRequestUrl(self.apiEndpoints.getGroups, null, false);
|
var url = self.helpers.createRequestUrl(self.apiEndpoints.getGroups, null, false);
|
||||||
return $.getJSON(url, function (res) {
|
return $.getJSON(url, function (res) {
|
||||||
successFunc(res);
|
successFunc(res);
|
||||||
//self.chosenUserDetails().Groups = res;
|
//self.chosenUserDetails().Groups = res;
|
||||||
//self.chosenUserDetails.valueHasMutated();
|
//self.chosenUserDetails.valueHasMutated();
|
||||||
}).fail(function (resp, status, error) {
|
}).fail(function (resp, status, error) {
|
||||||
console.log("error - getGroups");
|
console.log("error - getGroups");
|
||||||
var errObj = self.processRequestFailure(resp, status, error);
|
var errObj = self.helpers.processRequestFailure(resp, status, error);
|
||||||
self.assignErrorObject(errObj.errorCode, errObj.errorMessage, "getGroups");
|
self.assignErrorObject(errObj.errorCode, errObj.errorMessage, "getGroups");
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
self.createManualLog = function(newLog) {
|
||||||
|
var url = self.helpers.createRequestUrl(self.apiEndpoints.manualLogsCreate, null, false, false);
|
||||||
|
$.post(url, newLog, function () {
|
||||||
|
}, "json")
|
||||||
|
.done(function () {
|
||||||
|
self.manualLog(null);
|
||||||
|
$('#manualLogDialog').modal("hide");
|
||||||
|
self.goToMenuOption(self.uiPages.home());
|
||||||
|
})
|
||||||
|
.fail(function (resp, status, error) {
|
||||||
|
var errObj = self.helpers.processRequestFailure(resp, status, error);
|
||||||
|
self.assignErrorObject(errObj.errorCode, errObj.errorMessage, "createManualLog");
|
||||||
|
self.chosenUserDetails(null);
|
||||||
|
self.goToMenuOption(self.uiPages.home());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
self.deleteManualLog = function (logToDelete) {
|
||||||
|
var url = self.helpers.createRequestUrl(self.apiEndpoints.manualLogsDelete, null, false, false);
|
||||||
|
$.ajax({
|
||||||
|
url: url,
|
||||||
|
type: "DELETE",
|
||||||
|
data: logToDelete,
|
||||||
|
success: function (result) {
|
||||||
|
console.log("successfully deleted .." + result);
|
||||||
|
self.goToMenuOption(self.uiPages.home());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
self.createContextMenu = ko.observableArray([
|
||||||
|
{ text: "Create", action: createlog }
|
||||||
|
]);
|
||||||
|
self.editContextMenu = ko.observableArray([
|
||||||
|
{ text: "Create", action: createlog },
|
||||||
|
{ text: "Edit", action: editlog },
|
||||||
|
{ text: "Delete", action: deleteLog }
|
||||||
|
]);
|
||||||
|
function editlog (data) {
|
||||||
|
self.manualLog(data);
|
||||||
|
$('#manualLogDialog').modal("show");
|
||||||
|
$('#datetimepicker1').datetimepicker({
|
||||||
|
format: "YYYY-DD-MM HH:mm:ss",
|
||||||
|
date: new Date(data.EventTime),
|
||||||
|
minDate: moment(new Date(data.EventTime)).startOf('week'),
|
||||||
|
maxDate: moment(new Date(data.EventTime)).endOf('week')
|
||||||
|
});
|
||||||
|
self.assignUpdateHandler();
|
||||||
|
};
|
||||||
|
function createlog(data) {
|
||||||
|
self.manualLog({
|
||||||
|
CalendarWeek:-1,
|
||||||
|
Direction:-1,
|
||||||
|
EventTime: new Date().toISOString(),
|
||||||
|
Id: -1,
|
||||||
|
IdentifierId: -1,
|
||||||
|
UserId: self.chosenTimeLogUserId,
|
||||||
|
Year: 0
|
||||||
|
});
|
||||||
|
$('#manualLogDialog').modal("show");
|
||||||
|
$('#datetimepicker1').datetimepicker({
|
||||||
|
format: "YYYY-DD-MM HH:mm:ss",
|
||||||
|
minDate: moment(self.selectedTimeLogDate()).startOf("week"),
|
||||||
|
maxDate: moment(self.selectedTimeLogDate()).endOf("week")
|
||||||
|
});
|
||||||
|
self.assignUpdateHandler();
|
||||||
|
};
|
||||||
|
function deleteLog(data) {
|
||||||
|
if (confirm("Are you sure you want to delete this log?")) {
|
||||||
|
self.deleteManualLog(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
Sammy(function () {
|
Sammy(function () {
|
||||||
this.get("#users", function () {
|
this.get("#users", function () {
|
||||||
var query = this.params.query;
|
var query = this.params.query;
|
||||||
@ -389,9 +408,11 @@
|
|||||||
var pageNumber = this.params.pageNumber;
|
var pageNumber = this.params.pageNumber;
|
||||||
var groupId = this.params.groupId;
|
var groupId = this.params.groupId;
|
||||||
self.chosenMenuItemId("Home");
|
self.chosenMenuItemId("Home");
|
||||||
|
self.groupsList(null);
|
||||||
self.chosenUserDetails(null);
|
self.chosenUserDetails(null);
|
||||||
self.userList(null);
|
self.userList(null);
|
||||||
self.userTimeLogData(null);
|
self.userTimeLogData(null);
|
||||||
|
self.manualLog(null);
|
||||||
if (self.appDetails() === null) {
|
if (self.appDetails() === null) {
|
||||||
self.getAppDetails();
|
self.getAppDetails();
|
||||||
}
|
}
|
||||||
@ -405,18 +426,28 @@
|
|||||||
});
|
});
|
||||||
this.get("#userData/:userId", function () {
|
this.get("#userData/:userId", function () {
|
||||||
self.chosenMenuItemId("Data");
|
self.chosenMenuItemId("Data");
|
||||||
|
self.groupsList(null);
|
||||||
|
self.chosenUserDetails(null);
|
||||||
self.userList(null);
|
self.userList(null);
|
||||||
self.getUserDetails(this.params.userId);
|
|
||||||
self.userTimeLogData(null);
|
self.userTimeLogData(null);
|
||||||
|
self.manualLog(null);
|
||||||
|
self.getUserDetails(this.params.userId);
|
||||||
self.getUnassignedCardData();
|
self.getUnassignedCardData();
|
||||||
});
|
});
|
||||||
this.get("#timelogs/:userId", function () {
|
this.get("#timelogs/:userId", function () {
|
||||||
var selectedDate = this.params.selectedDate;
|
if (this.params.selectedDate) {
|
||||||
self.chosenMenuItemId("Other");
|
self.selectedTimeLogDate(this.params.selectedDate);
|
||||||
self.userList(null);
|
} else {
|
||||||
self.chosenUserDetails(null);
|
self.selectedTimeLogDate(new Date());
|
||||||
|
}
|
||||||
self.chosenTimeLogUserId = this.params.userId;
|
self.chosenTimeLogUserId = this.params.userId;
|
||||||
self.getTimeLogData(this.params.userId, selectedDate);
|
self.chosenMenuItemId("Other");
|
||||||
|
self.groupsList(null);
|
||||||
|
self.chosenUserDetails(null);
|
||||||
|
self.userList(null);
|
||||||
|
self.userTimeLogData(null);
|
||||||
|
self.manualLog(null);
|
||||||
|
self.getTimeLogData(this.params.userId, self.selectedTimeLogDate());
|
||||||
});
|
});
|
||||||
this.get("#newUser", function () {
|
this.get("#newUser", function () {
|
||||||
self.chosenMenuItemId("newUser");
|
self.chosenMenuItemId("newUser");
|
||||||
@ -455,14 +486,21 @@
|
|||||||
self.submitChangedUser(self.chosenUserDetails());
|
self.submitChangedUser(self.chosenUserDetails());
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
this.post("#manualLog",
|
||||||
|
function() {
|
||||||
|
self.createManualLog(self.manualLog());
|
||||||
|
|
||||||
|
$('#manualLogDialog').modal("hide");
|
||||||
|
//self.goToTimeLogs(self.chosenTimeLogUserId, null, [{ key: "selectedDate", value: self.selectedTimeLogDate() }]);
|
||||||
|
});
|
||||||
//default route (home page)
|
//default route (home page)
|
||||||
this.get("", function () { this.app.runRoute("get", "#" + self.uiPages.home()) });
|
this.get("", function () { this.app.runRoute("get", "#" + self.uiPages.home()) });
|
||||||
}).run();
|
}).run();
|
||||||
};
|
};
|
||||||
ko.applyBindings(new DataVM());
|
ko.applyBindings(new DataVM());
|
||||||
$(document).on("mouseenter", ".datepicker-days tbody tr", function () {
|
//$(document).on("mouseenter", ".datepicker-days tbody tr", function () {
|
||||||
$(this).addClass('highlight');
|
// $(this).addClass("highlight");
|
||||||
});
|
//});
|
||||||
$(document).on("mouseleave", ".datepicker-days tbody tr", function () {
|
//$(document).on("mouseleave", ".datepicker-days tbody tr", function () {
|
||||||
$(this).removeClass('highlight');
|
// $(this).removeClass("highlight");
|
||||||
});
|
//});
|
||||||
Loading…
Reference in New Issue
Block a user