From aed3bb1938008edc0919eafc9a78a4f07ea1f136 Mon Sep 17 00:00:00 2001 From: David Wolverton Date: Sat, 13 Jun 2015 13:48:53 -0400 Subject: [PATCH 01/12] Permissions change --- LICENSE.md | 0 README.md | 0 bigtime.js | 0 bower.json | 0 docs/notes.txt | 0 docs/testing-notes.txt | 0 images/jira-icon.png | Bin index.html | 0 script/bootstrap.js | 0 script/mytime/command/CreateTaskCommand.js | 0 script/mytime/command/CreateTimeEntryCommand.js | 0 script/mytime/command/DeleteTaskCommand.js | 0 script/mytime/command/DeleteTimeEntryCommand.js | 0 script/mytime/command/UpdateTaskCommand.js | 0 script/mytime/command/UpdateTimeEntryCommand.js | 0 script/mytime/command/_Command.js | 0 script/mytime/controller/TaskController.js | 0 script/mytime/controller/TimeEntryController.js | 0 script/mytime/controller/_CrudController.js | 0 script/mytime/debug-helper.js | 0 script/mytime/main.js | 0 script/mytime/mock-data.js | 0 script/mytime/model/Task.js | 0 script/mytime/model/TimeEntry.js | 0 script/mytime/model/_ModelBase.js | 0 script/mytime/model/modelRegistry.js | 0 script/mytime/persistence/Context.js | 0 script/mytime/persistence/IdGenerator.js | 0 script/mytime/persistence/ImporterExporter.js | 0 script/mytime/persistence/LocalStorage.js | 0 script/mytime/util/ColorGenerator.js | 0 script/mytime/util/Colors.js | 0 script/mytime/util/DateTimeUtil.js | 0 script/mytime/util/_StatefulSettersMixin.js | 0 script/mytime/util/generateUniqueId.js | 0 script/mytime/util/jira.js | 0 script/mytime/util/setIfDifferent.js | 0 .../util/store/EnhancedMemoryStore.QueryEngine.js | 0 script/mytime/util/store/EnhancedMemoryStore.js | 0 .../util/store/SingleDayFilteringTimeEntryStore.js | 0 script/mytime/util/store/StoreDrivenDom.js | 0 script/mytime/util/store/TransformingStoreView.js | 0 script/mytime/util/store/delegateObserve.js | 0 script/mytime/util/syncFrom.js | 0 script/mytime/util/whenAllPropertiesSet.js | 0 script/mytime/view/TimeEntryPane.html | 0 script/mytime/view/TimeEntryPane.js | 0 script/mytime/widget/DailyTimeList.js | 0 .../widget/DailyTimeList/templates/entry-edit.html | 0 .../widget/DailyTimeList/templates/entry.html | 0 script/mytime/widget/DailyTimeWidget.js | 0 .../widget/DailyTimeWidget/DailyTimeWidgetStore.js | 0 .../widget/DailyTimeWidget/DailyTimeWidgetView.js | 0 .../widget/DailyTimeWidget/templates/grid.html | 0 .../widget/DailyTimeWidget/templates/gridrow.html | 0 script/mytime/widget/DaysInWeekList.js | 0 script/mytime/widget/DaysInWeekList/template.html | 0 script/mytime/widget/TaskDialog.js | 0 script/mytime/widget/TaskForm.js | 0 script/mytime/widget/TaskForm/TaskFormContent.html | 0 script/mytime/widget/TaskPickerCombo.js | 0 script/mytime/widget/TaskPickerComboStore.js | 0 styles.css | 0 test.html | 0 test/bootstrap.js | 0 test/dojo/Stateful.spec.js | 0 test/dojo/store/Observable.spec.js | 0 test/mytime/DailyTimeWidget.spec.js | 0 test/mytime/controller/TimeEntryController.spec.js | 0 test/mytime/model/_ModelBase.spec.js | 0 test/mytime/persistence/LocalStorage.spec.js | 0 test/mytime/util/DateTimeUtil.spec.js | 0 test/mytime/util/jira.spec.js | 0 test/mytime/util/store/EnhancedMemoryStore.spec.js | 0 .../store/SingleDayFilteringTimeEntryStore.spec.js | 0 test/mytime/util/store/StoreDrivenDom.spec.js | 0 .../mytime/util/store/TransformingStoreView.spec.js | 0 test/mytime/util/store/delegateObserve.spec.js | 0 test/mytime/util/whenAllPropertiesSet.spec.js | 0 .../DailyTimeWidget/DailyTimeWidgetStore.spec.js | 0 .../DailyTimeWidget/DailyTimeWidgetView.spec.js | 0 test/mytime/widget/TaskForm.spec.js | 0 test/mytime/widget/TaskPickerCombo.spec.js | 0 test/tests.js | 0 84 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 LICENSE.md mode change 100644 => 100755 README.md mode change 100644 => 100755 bigtime.js mode change 100644 => 100755 bower.json mode change 100644 => 100755 docs/notes.txt mode change 100644 => 100755 docs/testing-notes.txt mode change 100644 => 100755 images/jira-icon.png mode change 100644 => 100755 index.html mode change 100644 => 100755 script/bootstrap.js mode change 100644 => 100755 script/mytime/command/CreateTaskCommand.js mode change 100644 => 100755 script/mytime/command/CreateTimeEntryCommand.js mode change 100644 => 100755 script/mytime/command/DeleteTaskCommand.js mode change 100644 => 100755 script/mytime/command/DeleteTimeEntryCommand.js mode change 100644 => 100755 script/mytime/command/UpdateTaskCommand.js mode change 100644 => 100755 script/mytime/command/UpdateTimeEntryCommand.js mode change 100644 => 100755 script/mytime/command/_Command.js mode change 100644 => 100755 script/mytime/controller/TaskController.js mode change 100644 => 100755 script/mytime/controller/TimeEntryController.js mode change 100644 => 100755 script/mytime/controller/_CrudController.js mode change 100644 => 100755 script/mytime/debug-helper.js mode change 100644 => 100755 script/mytime/main.js mode change 100644 => 100755 script/mytime/mock-data.js mode change 100644 => 100755 script/mytime/model/Task.js mode change 100644 => 100755 script/mytime/model/TimeEntry.js mode change 100644 => 100755 script/mytime/model/_ModelBase.js mode change 100644 => 100755 script/mytime/model/modelRegistry.js mode change 100644 => 100755 script/mytime/persistence/Context.js mode change 100644 => 100755 script/mytime/persistence/IdGenerator.js mode change 100644 => 100755 script/mytime/persistence/ImporterExporter.js mode change 100644 => 100755 script/mytime/persistence/LocalStorage.js mode change 100644 => 100755 script/mytime/util/ColorGenerator.js mode change 100644 => 100755 script/mytime/util/Colors.js mode change 100644 => 100755 script/mytime/util/DateTimeUtil.js mode change 100644 => 100755 script/mytime/util/_StatefulSettersMixin.js mode change 100644 => 100755 script/mytime/util/generateUniqueId.js mode change 100644 => 100755 script/mytime/util/jira.js mode change 100644 => 100755 script/mytime/util/setIfDifferent.js mode change 100644 => 100755 script/mytime/util/store/EnhancedMemoryStore.QueryEngine.js mode change 100644 => 100755 script/mytime/util/store/EnhancedMemoryStore.js mode change 100644 => 100755 script/mytime/util/store/SingleDayFilteringTimeEntryStore.js mode change 100644 => 100755 script/mytime/util/store/StoreDrivenDom.js mode change 100644 => 100755 script/mytime/util/store/TransformingStoreView.js mode change 100644 => 100755 script/mytime/util/store/delegateObserve.js mode change 100644 => 100755 script/mytime/util/syncFrom.js mode change 100644 => 100755 script/mytime/util/whenAllPropertiesSet.js mode change 100644 => 100755 script/mytime/view/TimeEntryPane.html mode change 100644 => 100755 script/mytime/view/TimeEntryPane.js mode change 100644 => 100755 script/mytime/widget/DailyTimeList.js mode change 100644 => 100755 script/mytime/widget/DailyTimeList/templates/entry-edit.html mode change 100644 => 100755 script/mytime/widget/DailyTimeList/templates/entry.html mode change 100644 => 100755 script/mytime/widget/DailyTimeWidget.js mode change 100644 => 100755 script/mytime/widget/DailyTimeWidget/DailyTimeWidgetStore.js mode change 100644 => 100755 script/mytime/widget/DailyTimeWidget/DailyTimeWidgetView.js mode change 100644 => 100755 script/mytime/widget/DailyTimeWidget/templates/grid.html mode change 100644 => 100755 script/mytime/widget/DailyTimeWidget/templates/gridrow.html mode change 100644 => 100755 script/mytime/widget/DaysInWeekList.js mode change 100644 => 100755 script/mytime/widget/DaysInWeekList/template.html mode change 100644 => 100755 script/mytime/widget/TaskDialog.js mode change 100644 => 100755 script/mytime/widget/TaskForm.js mode change 100644 => 100755 script/mytime/widget/TaskForm/TaskFormContent.html mode change 100644 => 100755 script/mytime/widget/TaskPickerCombo.js mode change 100644 => 100755 script/mytime/widget/TaskPickerComboStore.js mode change 100644 => 100755 styles.css mode change 100644 => 100755 test.html mode change 100644 => 100755 test/bootstrap.js mode change 100644 => 100755 test/dojo/Stateful.spec.js mode change 100644 => 100755 test/dojo/store/Observable.spec.js mode change 100644 => 100755 test/mytime/DailyTimeWidget.spec.js mode change 100644 => 100755 test/mytime/controller/TimeEntryController.spec.js mode change 100644 => 100755 test/mytime/model/_ModelBase.spec.js mode change 100644 => 100755 test/mytime/persistence/LocalStorage.spec.js mode change 100644 => 100755 test/mytime/util/DateTimeUtil.spec.js mode change 100644 => 100755 test/mytime/util/jira.spec.js mode change 100644 => 100755 test/mytime/util/store/EnhancedMemoryStore.spec.js mode change 100644 => 100755 test/mytime/util/store/SingleDayFilteringTimeEntryStore.spec.js mode change 100644 => 100755 test/mytime/util/store/StoreDrivenDom.spec.js mode change 100644 => 100755 test/mytime/util/store/TransformingStoreView.spec.js mode change 100644 => 100755 test/mytime/util/store/delegateObserve.spec.js mode change 100644 => 100755 test/mytime/util/whenAllPropertiesSet.spec.js mode change 100644 => 100755 test/mytime/widget/DailyTimeWidget/DailyTimeWidgetStore.spec.js mode change 100644 => 100755 test/mytime/widget/DailyTimeWidget/DailyTimeWidgetView.spec.js mode change 100644 => 100755 test/mytime/widget/TaskForm.spec.js mode change 100644 => 100755 test/mytime/widget/TaskPickerCombo.spec.js mode change 100644 => 100755 test/tests.js diff --git a/LICENSE.md b/LICENSE.md old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/bigtime.js b/bigtime.js old mode 100644 new mode 100755 diff --git a/bower.json b/bower.json old mode 100644 new mode 100755 diff --git a/docs/notes.txt b/docs/notes.txt old mode 100644 new mode 100755 diff --git a/docs/testing-notes.txt b/docs/testing-notes.txt old mode 100644 new mode 100755 diff --git a/images/jira-icon.png b/images/jira-icon.png old mode 100644 new mode 100755 diff --git a/index.html b/index.html old mode 100644 new mode 100755 diff --git a/script/bootstrap.js b/script/bootstrap.js old mode 100644 new mode 100755 diff --git a/script/mytime/command/CreateTaskCommand.js b/script/mytime/command/CreateTaskCommand.js old mode 100644 new mode 100755 diff --git a/script/mytime/command/CreateTimeEntryCommand.js b/script/mytime/command/CreateTimeEntryCommand.js old mode 100644 new mode 100755 diff --git a/script/mytime/command/DeleteTaskCommand.js b/script/mytime/command/DeleteTaskCommand.js old mode 100644 new mode 100755 diff --git a/script/mytime/command/DeleteTimeEntryCommand.js b/script/mytime/command/DeleteTimeEntryCommand.js old mode 100644 new mode 100755 diff --git a/script/mytime/command/UpdateTaskCommand.js b/script/mytime/command/UpdateTaskCommand.js old mode 100644 new mode 100755 diff --git a/script/mytime/command/UpdateTimeEntryCommand.js b/script/mytime/command/UpdateTimeEntryCommand.js old mode 100644 new mode 100755 diff --git a/script/mytime/command/_Command.js b/script/mytime/command/_Command.js old mode 100644 new mode 100755 diff --git a/script/mytime/controller/TaskController.js b/script/mytime/controller/TaskController.js old mode 100644 new mode 100755 diff --git a/script/mytime/controller/TimeEntryController.js b/script/mytime/controller/TimeEntryController.js old mode 100644 new mode 100755 diff --git a/script/mytime/controller/_CrudController.js b/script/mytime/controller/_CrudController.js old mode 100644 new mode 100755 diff --git a/script/mytime/debug-helper.js b/script/mytime/debug-helper.js old mode 100644 new mode 100755 diff --git a/script/mytime/main.js b/script/mytime/main.js old mode 100644 new mode 100755 diff --git a/script/mytime/mock-data.js b/script/mytime/mock-data.js old mode 100644 new mode 100755 diff --git a/script/mytime/model/Task.js b/script/mytime/model/Task.js old mode 100644 new mode 100755 diff --git a/script/mytime/model/TimeEntry.js b/script/mytime/model/TimeEntry.js old mode 100644 new mode 100755 diff --git a/script/mytime/model/_ModelBase.js b/script/mytime/model/_ModelBase.js old mode 100644 new mode 100755 diff --git a/script/mytime/model/modelRegistry.js b/script/mytime/model/modelRegistry.js old mode 100644 new mode 100755 diff --git a/script/mytime/persistence/Context.js b/script/mytime/persistence/Context.js old mode 100644 new mode 100755 diff --git a/script/mytime/persistence/IdGenerator.js b/script/mytime/persistence/IdGenerator.js old mode 100644 new mode 100755 diff --git a/script/mytime/persistence/ImporterExporter.js b/script/mytime/persistence/ImporterExporter.js old mode 100644 new mode 100755 diff --git a/script/mytime/persistence/LocalStorage.js b/script/mytime/persistence/LocalStorage.js old mode 100644 new mode 100755 diff --git a/script/mytime/util/ColorGenerator.js b/script/mytime/util/ColorGenerator.js old mode 100644 new mode 100755 diff --git a/script/mytime/util/Colors.js b/script/mytime/util/Colors.js old mode 100644 new mode 100755 diff --git a/script/mytime/util/DateTimeUtil.js b/script/mytime/util/DateTimeUtil.js old mode 100644 new mode 100755 diff --git a/script/mytime/util/_StatefulSettersMixin.js b/script/mytime/util/_StatefulSettersMixin.js old mode 100644 new mode 100755 diff --git a/script/mytime/util/generateUniqueId.js b/script/mytime/util/generateUniqueId.js old mode 100644 new mode 100755 diff --git a/script/mytime/util/jira.js b/script/mytime/util/jira.js old mode 100644 new mode 100755 diff --git a/script/mytime/util/setIfDifferent.js b/script/mytime/util/setIfDifferent.js old mode 100644 new mode 100755 diff --git a/script/mytime/util/store/EnhancedMemoryStore.QueryEngine.js b/script/mytime/util/store/EnhancedMemoryStore.QueryEngine.js old mode 100644 new mode 100755 diff --git a/script/mytime/util/store/EnhancedMemoryStore.js b/script/mytime/util/store/EnhancedMemoryStore.js old mode 100644 new mode 100755 diff --git a/script/mytime/util/store/SingleDayFilteringTimeEntryStore.js b/script/mytime/util/store/SingleDayFilteringTimeEntryStore.js old mode 100644 new mode 100755 diff --git a/script/mytime/util/store/StoreDrivenDom.js b/script/mytime/util/store/StoreDrivenDom.js old mode 100644 new mode 100755 diff --git a/script/mytime/util/store/TransformingStoreView.js b/script/mytime/util/store/TransformingStoreView.js old mode 100644 new mode 100755 diff --git a/script/mytime/util/store/delegateObserve.js b/script/mytime/util/store/delegateObserve.js old mode 100644 new mode 100755 diff --git a/script/mytime/util/syncFrom.js b/script/mytime/util/syncFrom.js old mode 100644 new mode 100755 diff --git a/script/mytime/util/whenAllPropertiesSet.js b/script/mytime/util/whenAllPropertiesSet.js old mode 100644 new mode 100755 diff --git a/script/mytime/view/TimeEntryPane.html b/script/mytime/view/TimeEntryPane.html old mode 100644 new mode 100755 diff --git a/script/mytime/view/TimeEntryPane.js b/script/mytime/view/TimeEntryPane.js old mode 100644 new mode 100755 diff --git a/script/mytime/widget/DailyTimeList.js b/script/mytime/widget/DailyTimeList.js old mode 100644 new mode 100755 diff --git a/script/mytime/widget/DailyTimeList/templates/entry-edit.html b/script/mytime/widget/DailyTimeList/templates/entry-edit.html old mode 100644 new mode 100755 diff --git a/script/mytime/widget/DailyTimeList/templates/entry.html b/script/mytime/widget/DailyTimeList/templates/entry.html old mode 100644 new mode 100755 diff --git a/script/mytime/widget/DailyTimeWidget.js b/script/mytime/widget/DailyTimeWidget.js old mode 100644 new mode 100755 diff --git a/script/mytime/widget/DailyTimeWidget/DailyTimeWidgetStore.js b/script/mytime/widget/DailyTimeWidget/DailyTimeWidgetStore.js old mode 100644 new mode 100755 diff --git a/script/mytime/widget/DailyTimeWidget/DailyTimeWidgetView.js b/script/mytime/widget/DailyTimeWidget/DailyTimeWidgetView.js old mode 100644 new mode 100755 diff --git a/script/mytime/widget/DailyTimeWidget/templates/grid.html b/script/mytime/widget/DailyTimeWidget/templates/grid.html old mode 100644 new mode 100755 diff --git a/script/mytime/widget/DailyTimeWidget/templates/gridrow.html b/script/mytime/widget/DailyTimeWidget/templates/gridrow.html old mode 100644 new mode 100755 diff --git a/script/mytime/widget/DaysInWeekList.js b/script/mytime/widget/DaysInWeekList.js old mode 100644 new mode 100755 diff --git a/script/mytime/widget/DaysInWeekList/template.html b/script/mytime/widget/DaysInWeekList/template.html old mode 100644 new mode 100755 diff --git a/script/mytime/widget/TaskDialog.js b/script/mytime/widget/TaskDialog.js old mode 100644 new mode 100755 diff --git a/script/mytime/widget/TaskForm.js b/script/mytime/widget/TaskForm.js old mode 100644 new mode 100755 diff --git a/script/mytime/widget/TaskForm/TaskFormContent.html b/script/mytime/widget/TaskForm/TaskFormContent.html old mode 100644 new mode 100755 diff --git a/script/mytime/widget/TaskPickerCombo.js b/script/mytime/widget/TaskPickerCombo.js old mode 100644 new mode 100755 diff --git a/script/mytime/widget/TaskPickerComboStore.js b/script/mytime/widget/TaskPickerComboStore.js old mode 100644 new mode 100755 diff --git a/styles.css b/styles.css old mode 100644 new mode 100755 diff --git a/test.html b/test.html old mode 100644 new mode 100755 diff --git a/test/bootstrap.js b/test/bootstrap.js old mode 100644 new mode 100755 diff --git a/test/dojo/Stateful.spec.js b/test/dojo/Stateful.spec.js old mode 100644 new mode 100755 diff --git a/test/dojo/store/Observable.spec.js b/test/dojo/store/Observable.spec.js old mode 100644 new mode 100755 diff --git a/test/mytime/DailyTimeWidget.spec.js b/test/mytime/DailyTimeWidget.spec.js old mode 100644 new mode 100755 diff --git a/test/mytime/controller/TimeEntryController.spec.js b/test/mytime/controller/TimeEntryController.spec.js old mode 100644 new mode 100755 diff --git a/test/mytime/model/_ModelBase.spec.js b/test/mytime/model/_ModelBase.spec.js old mode 100644 new mode 100755 diff --git a/test/mytime/persistence/LocalStorage.spec.js b/test/mytime/persistence/LocalStorage.spec.js old mode 100644 new mode 100755 diff --git a/test/mytime/util/DateTimeUtil.spec.js b/test/mytime/util/DateTimeUtil.spec.js old mode 100644 new mode 100755 diff --git a/test/mytime/util/jira.spec.js b/test/mytime/util/jira.spec.js old mode 100644 new mode 100755 diff --git a/test/mytime/util/store/EnhancedMemoryStore.spec.js b/test/mytime/util/store/EnhancedMemoryStore.spec.js old mode 100644 new mode 100755 diff --git a/test/mytime/util/store/SingleDayFilteringTimeEntryStore.spec.js b/test/mytime/util/store/SingleDayFilteringTimeEntryStore.spec.js old mode 100644 new mode 100755 diff --git a/test/mytime/util/store/StoreDrivenDom.spec.js b/test/mytime/util/store/StoreDrivenDom.spec.js old mode 100644 new mode 100755 diff --git a/test/mytime/util/store/TransformingStoreView.spec.js b/test/mytime/util/store/TransformingStoreView.spec.js old mode 100644 new mode 100755 diff --git a/test/mytime/util/store/delegateObserve.spec.js b/test/mytime/util/store/delegateObserve.spec.js old mode 100644 new mode 100755 diff --git a/test/mytime/util/whenAllPropertiesSet.spec.js b/test/mytime/util/whenAllPropertiesSet.spec.js old mode 100644 new mode 100755 diff --git a/test/mytime/widget/DailyTimeWidget/DailyTimeWidgetStore.spec.js b/test/mytime/widget/DailyTimeWidget/DailyTimeWidgetStore.spec.js old mode 100644 new mode 100755 diff --git a/test/mytime/widget/DailyTimeWidget/DailyTimeWidgetView.spec.js b/test/mytime/widget/DailyTimeWidget/DailyTimeWidgetView.spec.js old mode 100644 new mode 100755 diff --git a/test/mytime/widget/TaskForm.spec.js b/test/mytime/widget/TaskForm.spec.js old mode 100644 new mode 100755 diff --git a/test/mytime/widget/TaskPickerCombo.spec.js b/test/mytime/widget/TaskPickerCombo.spec.js old mode 100644 new mode 100755 diff --git a/test/tests.js b/test/tests.js old mode 100644 new mode 100755 From 9687e0509e9239bc0dcb753cf96e3ac26b36b008 Mon Sep 17 00:00:00 2001 From: David Wolverton Date: Sat, 13 Jun 2015 15:50:23 -0400 Subject: [PATCH 02/12] initial merge from Vodori Somday work --- bower.json | 10 +- index.html | 17 +- script/bootstrap.js | 2 +- .../mytime/command/GetJiraPickListCommand.js | 12 + .../command/UpdateJiraIntegrationCommand.js | 12 + script/mytime/controller/JiraController.js | 28 ++ script/mytime/controller/TaskController.js | 18 +- .../mytime/controller/TimeEntryController.js | 21 +- script/mytime/controller/_CrudController.js | 78 +++-- script/mytime/main.js | 16 +- script/mytime/mock-data.js | 8 +- script/mytime/model/Task.js | 21 +- script/mytime/model/TimeEntry.js | 5 +- script/mytime/persistence/LocalStorage.js | 22 +- script/mytime/rest/DeleteEntryRequest.js | 18 ++ script/mytime/rest/DeleteTaskRequest.js | 18 ++ script/mytime/rest/GetJiraPicklistRequest.js | 21 ++ script/mytime/rest/PutEntryRequest.js | 23 ++ script/mytime/rest/PutTaskRequest.js | 22 ++ script/mytime/rest/RequestQueue.js | 107 +++++++ script/mytime/store/JiraPicklistStore.js | 44 +++ script/mytime/view/TimeEntryPane.html | 2 - script/mytime/view/TimeEntryPane.js | 9 +- script/mytime/widget/DailyTimeList.js | 267 ------------------ .../DailyTimeList/templates/entry-edit.html | 19 -- .../widget/DailyTimeList/templates/entry.html | 19 -- script/mytime/widget/DailyTimeWidget.js | 22 +- .../DailyTimeWidget/DailyTimeWidgetStore.js | 2 +- .../DailyTimeWidget/DailyTimeWidgetView.js | 12 +- script/mytime/widget/JiraPickerCombo.js | 53 ++++ script/mytime/widget/TaskDialog.js | 67 ----- script/mytime/widget/TaskForm.js | 50 ---- .../widget/TaskForm/TaskFormContent.html | 20 -- script/mytime/widget/TaskPickerCombo.js | 76 +++-- script/mytime/widget/TaskPickerComboStore.js | 23 +- script/mytime/widget/TimeEntryDetails.js | 229 +++++++++++++++ .../TimeEntryDetails/TimeEntryDetailsView.js | 101 +++++++ .../templates/TimeEntryDetails.html | 50 ++++ 38 files changed, 972 insertions(+), 572 deletions(-) create mode 100755 script/mytime/command/GetJiraPickListCommand.js create mode 100755 script/mytime/command/UpdateJiraIntegrationCommand.js create mode 100755 script/mytime/controller/JiraController.js create mode 100755 script/mytime/rest/DeleteEntryRequest.js create mode 100755 script/mytime/rest/DeleteTaskRequest.js create mode 100755 script/mytime/rest/GetJiraPicklistRequest.js create mode 100755 script/mytime/rest/PutEntryRequest.js create mode 100755 script/mytime/rest/PutTaskRequest.js create mode 100755 script/mytime/rest/RequestQueue.js create mode 100755 script/mytime/store/JiraPicklistStore.js delete mode 100755 script/mytime/widget/DailyTimeList.js delete mode 100755 script/mytime/widget/DailyTimeList/templates/entry-edit.html delete mode 100755 script/mytime/widget/DailyTimeList/templates/entry.html create mode 100755 script/mytime/widget/JiraPickerCombo.js delete mode 100755 script/mytime/widget/TaskDialog.js delete mode 100755 script/mytime/widget/TaskForm.js delete mode 100755 script/mytime/widget/TaskForm/TaskFormContent.html create mode 100755 script/mytime/widget/TimeEntryDetails.js create mode 100755 script/mytime/widget/TimeEntryDetails/TimeEntryDetailsView.js create mode 100755 script/mytime/widget/TimeEntryDetails/templates/TimeEntryDetails.html diff --git a/bower.json b/bower.json index d1aac26..a255e76 100755 --- a/bower.json +++ b/bower.json @@ -1,11 +1,11 @@ { "name": "mytime", - "version": "0.0", + "version": "1.0", "dependencies": { - "dojo": "1.8.4", - "dojox": "1.8.4", - "dijit": "1.8.4", - "lodash": "2.4.1" + "dojo": "1.10", + "dojox": "1.10", + "dijit": "1.10", + "lodash": "3.8.0" }, "devDependencies": { "mocha": "*", diff --git a/index.html b/index.html index 2e5a729..5e8ed7f 100755 --- a/index.html +++ b/index.html @@ -1,9 +1,10 @@ - + + - Time Logger - + My Time + -
-
-
- +
+ \ No newline at end of file diff --git a/script/bootstrap.js b/script/bootstrap.js index ae32fad..442736c 100755 --- a/script/bootstrap.js +++ b/script/bootstrap.js @@ -15,7 +15,7 @@ require({ packages: [ { name: 'mytime', location: '../../script/mytime' }, - { name: 'lodash', location: '../lodash/dist', main: 'lodash.min' } + { name: 'lodash', location: '../lodash', main: 'lodash.min' } ] }, ['mytime/debug-helper', 'dojo/parser', 'dojo/ready'].concat(main), function(_1, parser, ready) { ready(function() { diff --git a/script/mytime/command/GetJiraPickListCommand.js b/script/mytime/command/GetJiraPickListCommand.js new file mode 100755 index 0000000..10b6adc --- /dev/null +++ b/script/mytime/command/GetJiraPickListCommand.js @@ -0,0 +1,12 @@ +/** + * @license + * Copyright 2014 David Wolverton + * Available under MIT license + */ +define(["./_Command"], +function (_Command) { + return _Command.makeCommand({ + commandTopic: "integration/jira/list", + query: null + }); +}); \ No newline at end of file diff --git a/script/mytime/command/UpdateJiraIntegrationCommand.js b/script/mytime/command/UpdateJiraIntegrationCommand.js new file mode 100755 index 0000000..b02a7db --- /dev/null +++ b/script/mytime/command/UpdateJiraIntegrationCommand.js @@ -0,0 +1,12 @@ +/** + * @license + * Copyright 2014 David Wolverton + * Available under MIT license + */ +define(["./_Command"], +function (_Command) { + return _Command.makeCommand({ + commandTopic: "time-entry/update", + timeEntry: null + }); +}); \ No newline at end of file diff --git a/script/mytime/controller/JiraController.js b/script/mytime/controller/JiraController.js new file mode 100755 index 0000000..6ba9e59 --- /dev/null +++ b/script/mytime/controller/JiraController.js @@ -0,0 +1,28 @@ +define(['dojo/_base/lang', 'dojo/_base/declare', "dijit/Destroyable", + "mytime/command/GetJiraPicklistCommand", "mytime/rest/GetJiraPicklistRequest"], +function (lang, declare, Destroyable, + GetJiraPicklistCommand, GetJiraPicklistRequest) { + + return declare([Destroyable], { + + requestQueue: null, + + constructor: function(args) { + lang.mixin(this, args); + this.own( + GetJiraPicklistCommand.subscribe(lang.hitch(this, "handlePicklist")) + ); + }, + + handlePicklist: function(command) { + var request = new GetJiraPicklistRequest(command.query); + request.then(lang.hitch(command, 'resolve')); + this.requestQueue.push(request); + }, + + handleUpdate: function(command) { + + } + + }); +}); \ No newline at end of file diff --git a/script/mytime/controller/TaskController.js b/script/mytime/controller/TaskController.js index 911f7f4..a45e1fb 100755 --- a/script/mytime/controller/TaskController.js +++ b/script/mytime/controller/TaskController.js @@ -8,12 +8,14 @@ define([ "mytime/model/modelRegistry", "mytime/model/Task", "mytime/command/CreateTaskCommand", "mytime/command/UpdateTaskCommand", "mytime/command/DeleteTaskCommand", + "mytime/rest/PutTaskRequest", "mytime/rest/DeleteTaskRequest", "mytime/controller/_CrudController", "mytime/util/syncFrom", "mytime/util/ColorGenerator" ], function( lang, declare, when, modelRegistry, Task, CreateTaskCommand, UpdateTaskCommand, DeleteTaskCommand, + PutTaskRequest, DeleteTaskRequest, _CrudController, syncFrom, ColorGenerator ) { @@ -35,8 +37,10 @@ define([ colorGenerator: null, timeEntryStore: null, + requestQueue: null, - constructor: function() { + constructor: function(args) { + lang.mixin(this, args); this.colorGenerator = new ColorGenerator(); this.own( syncFrom(modelRegistry, "taskStore", this, "store") ); this.own( syncFrom(modelRegistry, "timeEntryStore", this) ); @@ -61,6 +65,18 @@ define([ this.timeEntryStore.put(timeEntry); }, this); })); + }, + + _afterCreate: function(command, task) { + //this.requestQueue.push(new PutTaskRequest(task)); + }, + + _afterUpdate: function(command, task) { + //this.requestQueue.push(new PutTaskRequest(task)); + }, + + _afterDelete: function(command, task) { + //this.requestQueue.push(new DeleteTaskRequest(task)); } }); diff --git a/script/mytime/controller/TimeEntryController.js b/script/mytime/controller/TimeEntryController.js index ac3358f..4e67f40 100755 --- a/script/mytime/controller/TimeEntryController.js +++ b/script/mytime/controller/TimeEntryController.js @@ -4,16 +4,18 @@ * Available under MIT license */ define([ - "dojo/_base/declare", + "dojo/_base/declare", "dojo/_base/lang", "mytime/model/modelRegistry", "mytime/model/TimeEntry", "mytime/command/CreateTimeEntryCommand", "mytime/command/UpdateTimeEntryCommand", "mytime/command/DeleteTimeEntryCommand", + "mytime/rest/PutEntryRequest", "mytime/rest/DeleteEntryRequest", "mytime/controller/_CrudController", "mytime/util/syncFrom" ], function( - declare, + declare, lang, modelRegistry, TimeEntry, CreateTimeEntryCommand, UpdateTimeEntryCommand, DeleteTimeEntryCommand, + PutEntryRequest, DeleteEntryRequest, _CrudController, syncFrom ) { @@ -32,7 +34,8 @@ define([ objectTypeStringForMessages: "time entry", storageKey: "timeEntryStore", - constructor: function() { + constructor: function(args) { + lang.mixin(this, args); this.own( syncFrom(modelRegistry, "timeEntryStore", this, "store") ); }, @@ -56,6 +59,18 @@ define([ entry.endHour = swap; } return true; + }, + + _afterCreate: function(command, entry) { + //this.requestQueue.push(new PutEntryRequest(entry)); + }, + + _afterUpdate: function(command, entry) { + //this.requestQueue.push(new PutEntryRequest(entry)); + }, + + _afterDelete: function(command, entry) { + //this.requestQueue.push(new DeleteEntryRequest(entry)); } }); diff --git a/script/mytime/controller/_CrudController.js b/script/mytime/controller/_CrudController.js index d0dc567..a6f13e6 100755 --- a/script/mytime/controller/_CrudController.js +++ b/script/mytime/controller/_CrudController.js @@ -48,18 +48,19 @@ define([ if (!this.store) { command.reject(this._getCommandError("Cannot add {} before system is initialized.")); } else { - var entry = new this.objectTypeConstructor(command[this.commandObjectProperty]); - entry.set("id", IdGenerator.nextIdForType(this.objectTypeName)); + var object = new this.objectTypeConstructor(command[this.commandObjectProperty]); + object.set("id", IdGenerator.nextIdForType(this.objectTypeName)); - this._beforeCreate(command, entry); + this._beforeCreate(command, object); if (command.isFulfilled()) { return; } - console.log("PUT NEW " + JSON.stringify(entry)); - this.store.put(entry); - command.resolve(this._getCommandResult(entry)); + console.log("PUT NEW " + JSON.stringify(object)); + this.store.put(object); + command.resolve(this._getCommandResult(object)); this._persistStore(); + this._afterCreate(command, object); } }, @@ -68,10 +69,19 @@ define([ * resolve or reject the command. * * @param {Object} command - * @param {Object} entry new object about to be created. an instance of objectTypeConstructor + * @param {Object} object new object about to be created. an instance of objectTypeConstructor * @private */ - _beforeCreate: function(command, entry) {}, + _beforeCreate: function(command, object) {}, + + /** + * Override this to extend behavior. Called after creating a new object. + * + * @param {Object} command + * @param {Object} object new object created. an instance of objectTypeConstructor + * @private + */ + _afterCreate: function(command, object) {}, handleUpdate: function(command) { if (!this.store) { @@ -79,22 +89,23 @@ define([ } else { var updateObject = command[this.commandObjectProperty]; var id = updateObject.id; - var existingEntry = this.store.get(id); - if (!existingEntry) { + var existingObject = this.store.get(id); + if (!existingObject) { command.reject(this._getCommandError("Cannot update {}. It does not exist.")); return; } - this._beforeUpdate(command, existingEntry); + this._beforeUpdate(command, existingObject); if (command.isFulfilled()) { return; } - existingEntry.updateFrom(updateObject); - console.log("PUT " + JSON.stringify(existingEntry)); - this.store.put(existingEntry); - command.resolve(this._getCommandResult(existingEntry)); + existingObject.updateFrom(updateObject); + console.log("PUT " + JSON.stringify(existingObject)); + this.store.put(existingObject); + command.resolve(this._getCommandResult(existingObject)); this._persistStore(); + this._afterUpdate(command, existingObject); } }, @@ -103,31 +114,41 @@ define([ * or reject the command. * * @param command - * @param existingEntry the entry from the store before updates are applied + * @param existingObject the object from the store before updates are applied + * @private + */ + _beforeUpdate: function(command, existingObject) {}, + + /** + * Override this to extend behavior. Called after updating an object. + * + * @param {Object} command + * @param {Object} object in the store after updates made. an instance of objectTypeConstructor * @private */ - _beforeUpdate: function(command, existingEntry) {}, + _afterUpdate: function(command, object) {}, handleDelete: function(command) { if (!this.store) { command.reject(this._getCommandError("Cannot delete {} before system is initialized.")); } else { var id = command[this.commandIdProperty]; - var existingEntry = this.store.get(id); - if (!existingEntry) { + var existingObject = this.store.get(id); + if (!existingObject) { command.reject(this._getCommandError("Cannot delete {}. It does not exist.")); return; } - this._beforeDelete(command, existingEntry); + this._beforeDelete(command, existingObject); if (command.isFulfilled()) { return; } - console.log("REMOVE " + JSON.stringify(existingEntry)); + console.log("REMOVE " + JSON.stringify(existingObject)); this.store.remove(id); - command.resolve(this._getCommandResult(existingEntry, id)); + command.resolve(this._getCommandResult(existingObject, id)); this._persistStore(); + this._afterDelete(command, existingObject); } }, @@ -136,10 +157,19 @@ define([ * or reject the command. * * @param command - * @param existingEntry the entry from the store that will be deleted. + * @param existingObject the object from the store that will be deleted. + * @private + */ + _beforeDelete: function(command, existingObject) {}, + + /** + * Override this to extend behavior. Called after deleting an object. + * + * @param {Object} command + * @param {Object} object that was removed from the store. an instance of objectTypeConstructor * @private */ - _beforeDelete: function(command, existingEntry) {}, + _afterDelete: function(command, existingObject) {}, _getCommandResult: function(object, id) { var result = {}; diff --git a/script/mytime/main.js b/script/mytime/main.js index 59f7a6c..b262156 100755 --- a/script/mytime/main.js +++ b/script/mytime/main.js @@ -6,26 +6,30 @@ define([ "mytime/model/modelRegistry", "mytime/model/TimeEntry", "mytime/model/Task", - "mytime/controller/TimeEntryController", "mytime/controller/TaskController", + "mytime/controller/TimeEntryController", "mytime/controller/TaskController", "mytime/controller/JiraController", + "mytime/rest/RequestQueue", "mytime/util/store/EnhancedMemoryStore", "mytime/persistence/LocalStorage", "mytime/mock-data" ], function( modelRegistry, TimeEntry, Task, - TimeEntryController, TaskController, + TimeEntryController, TaskController, JiraController, + RequestQueue, EnhancedMemoryStore, LocalStorage, mockData ) { modelRegistry.set("timeEntryStore", EnhancedMemoryStore.createObservable()); modelRegistry.set("taskStore", EnhancedMemoryStore.createObservable()); - + LocalStorage.loadStore("timeEntryStore", modelRegistry.get("timeEntryStore"), TimeEntry); LocalStorage.loadStore("taskStore", modelRegistry.get("taskStore"), Task); - new TimeEntryController(); - new TaskController(); + var requestQueue = new RequestQueue(); + new TimeEntryController({ requestQueue: requestQueue }); + new TaskController({ requestQueue: requestQueue }); + new JiraController({ requestQueue: requestQueue }); -// mockData(); + //mockData(); }); \ No newline at end of file diff --git a/script/mytime/mock-data.js b/script/mytime/mock-data.js index 07a7c7f..59eb0eb 100755 --- a/script/mytime/mock-data.js +++ b/script/mytime/mock-data.js @@ -9,10 +9,10 @@ define([ ], function(CreateTaskCommand, CreateTimeEntryCommand, DateTimeUtil) { return function() { - new CreateTaskCommand({ task: { code: "CAYENNE-1234", name: "Squash a Bug" } }).exec(); - new CreateTaskCommand({ task: { code: "CAYENNE-456", name: "Make it Work" } }).exec(); - new CreateTaskCommand({ task: { code: "CAYENNE-789", name: "Do Something Awesome" } }).exec(); - new CreateTaskCommand({ task: { code: "PSP-100", name: "Uh Oh..." } }).exec(); + new CreateTaskCommand({ task: { description: "CAYENNE-1234 Squash a Bug" } }).exec(); + new CreateTaskCommand({ task: { description: "CAYENNE-456 Make it Work" } }).exec(); + new CreateTaskCommand({ task: { description: "CAYENNE-789 Do Something Awesome" } }).exec(); + new CreateTaskCommand({ task: { description: "PSP-100 Uh Oh..." } }).exec(); new CreateTimeEntryCommand({ timeEntry: { date: DateTimeUtil.getCurrentDate(), startHour: 8.5, endHour: 9.75, diff --git a/script/mytime/model/Task.js b/script/mytime/model/Task.js index 33bfcd3..f7ebe94 100755 --- a/script/mytime/model/Task.js +++ b/script/mytime/model/Task.js @@ -10,26 +10,13 @@ define([ module, declare, _ModelBase ) { var Task = declare(module.id, [_ModelBase], { - _propertyNames: ["id", "code", "name", "color"], + _propertyNames: ["id", "description", "color", "integrations"], id: null, - code: null, - name: null, - color: null + description: null, + color: null, + integrations: null }); - /** - * "static" method to build a string for the task, including code and name if available. - * @param task - * @returns {string} - */ - Task.getDisplayText = function(task) { - var text = task.code || ""; - if (task.name) { - text += " " + task.name; - } - return text; - }; - return Task; }); \ No newline at end of file diff --git a/script/mytime/model/TimeEntry.js b/script/mytime/model/TimeEntry.js index a660d37..fce7f16 100755 --- a/script/mytime/model/TimeEntry.js +++ b/script/mytime/model/TimeEntry.js @@ -8,7 +8,7 @@ define([ "mytime/model/_ModelBase" ], function (module, declare, _ModelBase) { return declare(module.id, [_ModelBase], { - _propertyNames: ["id", "date", "startHour", "endHour", "text", "taskId"], + _propertyNames: ["id", "date", "startHour", "endHour", "text", "taskId", "integrations"], id: null, date: null, @@ -16,6 +16,7 @@ define([ endHour: null, text: null, - taskId: null + taskId: null, + integrations: null }); }); \ No newline at end of file diff --git a/script/mytime/persistence/LocalStorage.js b/script/mytime/persistence/LocalStorage.js index 14c7410..b968e37 100755 --- a/script/mytime/persistence/LocalStorage.js +++ b/script/mytime/persistence/LocalStorage.js @@ -13,13 +13,22 @@ function (exports, _, lang, Context) { */ lang.mixin(exports, { + /** + * The object is automatically stored specifically for the current context. + */ persistObject: function(key, object) { key = this._getKeyForContext(key); + this.persistObjectWithoutContext(key, object); + }, + + /** + * The object is stored in a way that is shared between all contexts. + */ + persistObjectWithoutContext: function(key, object) { localStorage.setItem(key, JSON.stringify(object)); }, /** - * * @param {string} key * @param {function} [constructor] if specified, the retrieved object will be passed into the constructor to * return an object of that type (optional - if not specified the raw persisted data is @@ -28,6 +37,17 @@ function (exports, _, lang, Context) { */ retrieveObject: function(key, constructor) { key = this._getKeyForContext(key); + return this.retrieveObjectWithoutContext(key, constructor); + }, + + /** + * @param {string} key + * @param {function} [constructor] if specified, the retrieved object will be passed into the constructor to + * return an object of that type (optional - if not specified the raw persisted data is + * returned. + * @returns {*} + */ + retrieveObjectWithoutContext: function(key, constructor) { var object = localStorage.getItem(key); if (!object) { return null; diff --git a/script/mytime/rest/DeleteEntryRequest.js b/script/mytime/rest/DeleteEntryRequest.js new file mode 100755 index 0000000..155d487 --- /dev/null +++ b/script/mytime/rest/DeleteEntryRequest.js @@ -0,0 +1,18 @@ +/** + * @license + * Copyright 2014 David Wolverton + * Available under MIT license + */ +define(["lodash", "dojo/_base/declare", "dojo/string"], +function (_, declare, string) { + + return declare([], { + method: 'delete', + url: '/api/entires/${id}', + + constructor: function(entry) { + this.url = string.substitute(this.url, entry); + } + }); +}); + diff --git a/script/mytime/rest/DeleteTaskRequest.js b/script/mytime/rest/DeleteTaskRequest.js new file mode 100755 index 0000000..a5de448 --- /dev/null +++ b/script/mytime/rest/DeleteTaskRequest.js @@ -0,0 +1,18 @@ +/** + * @license + * Copyright 2014 David Wolverton + * Available under MIT license + */ +define(["lodash", "dojo/_base/declare", "dojo/string"], +function (_, declare, string) { + + return declare([], { + method: 'delete', + url: '/api/tasks/${id}', + + constructor: function(task) { + this.url = string.substitute(this.url, task); + } + }); +}); + diff --git a/script/mytime/rest/GetJiraPicklistRequest.js b/script/mytime/rest/GetJiraPicklistRequest.js new file mode 100755 index 0000000..7454dfd --- /dev/null +++ b/script/mytime/rest/GetJiraPicklistRequest.js @@ -0,0 +1,21 @@ +/** + * @license + * Copyright 2014 David Wolverton + * Available under MIT license + */ +define(["lodash", "dojo/_base/declare", "dojo/Deferred"], +function (_, declare, Deferred) { + + return declare([Deferred], { + method: "get", + url: "/api/integrations/jira", + + constructor: function(queryString) { + this.inherited(arguments, []); + if (queryString) { + this.query = { "q": queryString } + } + } + }); +}); + diff --git a/script/mytime/rest/PutEntryRequest.js b/script/mytime/rest/PutEntryRequest.js new file mode 100755 index 0000000..6d2e0e0 --- /dev/null +++ b/script/mytime/rest/PutEntryRequest.js @@ -0,0 +1,23 @@ +/** + * @license + * Copyright 2014 David Wolverton + * Available under MIT license + */ +define(["lodash", "dojo/_base/declare", "dojo/string"], +function (_, declare, string) { + + return declare([], { + method: 'put', + url: '/api/entries/${id}', + + constructor: function(entry) { + this.url = string.substitute(this.url, entry); + this.data = { + taskId: entry.taskId, + start: entry.date + "T" + entry.startHour + ":00:00", + length: (entry.endHour - entry.startHour) * 60 + } + } + }); +}); + diff --git a/script/mytime/rest/PutTaskRequest.js b/script/mytime/rest/PutTaskRequest.js new file mode 100755 index 0000000..f061b0b --- /dev/null +++ b/script/mytime/rest/PutTaskRequest.js @@ -0,0 +1,22 @@ +/** + * @license + * Copyright 2014 David Wolverton + * Available under MIT license + */ +define(["lodash", "dojo/_base/declare", "dojo/string"], +function (_, declare, string) { + + return declare([], { + method: 'put', + url: '/api/tasks/${id}', + + constructor: function(task) { + this.url = string.substitute(this.url, task); + this.data = { + description: task.description, + color: task.color + } + } + }); +}); + diff --git a/script/mytime/rest/RequestQueue.js b/script/mytime/rest/RequestQueue.js new file mode 100755 index 0000000..712673e --- /dev/null +++ b/script/mytime/rest/RequestQueue.js @@ -0,0 +1,107 @@ +/** + * @license + * Copyright 2014 David Wolverton + * Available under MIT license + */ +define(["lodash", "dojo/_base/lang", "dojo/_base/declare", "dojo/request/xhr", "mytime/persistence/LocalStorage"], +function (_, lang, declare, xhr, LocalStorage) { + + return declare([], { + + baseUrl: "", + + baseHeaders: { + "Content-type": "application/json" + }, + + authHeaders: { + jira: "ABC", + bigtime: "DEF" + }, + + _queue: null, + _requestInProgress: false, + + constructor: function() { + this._queue = LocalStorage.retrieveObjectWithoutContext("requestQueue"); + if (!this._queue) { + this._queue = []; + } + }, + + postConstruct: function() { + this._trigger(); + }, + + push: function(request) { + this._enqueue(request); + this._trigger(); + }, + + _trigger: function() { + if (!this._requestInProgress) { + this._doNext(); + } + }, + + _doNext: function() { + if (this._queue.length != 0) { + this._requestInProgress = true; + this._do(this._queue[0]); + } + }, + + _do: function(request) { + var url = this.baseUrl + request.url; + var args = { + handleAs: "json", + method: request.method, + headers: this._getHeaders() + }; + if (request.data) { + args.data = JSON.stringify(request.data); + } + if (request.query) { + args.query = request.query; + } + + xhr(url, args).then(lang.hitch(this, function(response) { + console.log("RESPONSE: ", response); + if (typeof request.resolve === 'function') { + request.resolve(response); + } + this._finishedWithCurrentRequest(); + }), lang.hitch(this, function(err) { + console.log("RESPONSE ERROR: ", err); + // note: in Chrome get response code 0 if cannot connect to server. + if (typeof request.reject === 'function') { + request.reject(err); + } + this._finishedWithCurrentRequest(); + })); + }, + + _finishedWithCurrentRequest: function() { + this._requestInProgress = false; + this._dequeue(); + this._doNext(); + }, + + _getHeaders: function() { + var headers = lang.mixin({}, this.baseHeaders); + headers["Integration-Auth-Tokens"] = JSON.stringify(this.authHeaders); + return headers; + }, + + _enqueue: function(request) { + this._queue.push(request); + LocalStorage.persistObjectWithoutContext("requestQueue", this._queue); + }, + + _dequeue: function() { + this._queue.shift(); + LocalStorage.persistObjectWithoutContext("requestQueue", this._queue); + } + + }); +}); \ No newline at end of file diff --git a/script/mytime/store/JiraPicklistStore.js b/script/mytime/store/JiraPicklistStore.js new file mode 100755 index 0000000..ad18158 --- /dev/null +++ b/script/mytime/store/JiraPicklistStore.js @@ -0,0 +1,44 @@ +/** + * @license + * Copyright 2014 David Wolverton + * Available under MIT license + */ +define(["lodash", "dojo/_base/declare", "dojo/_base/lang", "dojo/Deferred", "mytime/command/GetJiraPickListCommand"], +function (_, declare, lang, Deferred, GetJiraPickListCommand) { + return declare([], { + + get: function(id) { + return this.query(id).then(function(results) { + return results.length == 1 ? results[0] : null; + }); + }, + + query: function(query) { + query = this._normalizeQuery(query); + var deferred = new Deferred(); + new GetJiraPickListCommand({query: query}).exec().then(function(results) { + _.forEach(results, function(item) { + item.label = item.id + ' ' + item.description; + }); + deferred.resolve(results); + }); + return deferred; + }, + + _normalizeQuery: function(query) { + if (!query) { + return null; + } else if (typeof query === 'string') { + return query; + } else if (query.label) { + return this._normalizeQuery(query.label.toString()); + } else { + return null; + } + }, + + getIdentity: function(object) { + return object ? object.id : null; + } + }); +}); \ No newline at end of file diff --git a/script/mytime/view/TimeEntryPane.html b/script/mytime/view/TimeEntryPane.html index df884cc..024457c 100755 --- a/script/mytime/view/TimeEntryPane.html +++ b/script/mytime/view/TimeEntryPane.html @@ -3,6 +3,4 @@
- -
\ No newline at end of file diff --git a/script/mytime/view/TimeEntryPane.js b/script/mytime/view/TimeEntryPane.js index f403240..a16aeca 100755 --- a/script/mytime/view/TimeEntryPane.js +++ b/script/mytime/view/TimeEntryPane.js @@ -13,7 +13,7 @@ define([ 'dojox/mvc/sync', 'dojo/text!./TimeEntryPane.html', /* In template: */ - 'mytime/widget/DaysInWeekList', 'mytime/widget/DailyTimeWidget', 'mytime/widget/DailyTimeList' + 'mytime/widget/DaysInWeekList', 'mytime/widget/DailyTimeWidget' ], function ( _, lang, declare, _WidgetBase, @@ -29,22 +29,17 @@ define([ templateString: template, _daysInWeekList: null, _dailyTimeWidget: null, - _dailyTimeList: null, currentDate: DateTimeUtil.getCurrentDate(), postCreate: function() { this.own(sync(this, 'currentDate', this._daysInWeekList, 'selectedDate')); this.own(sync(this, 'currentDate', this._dailyTimeWidget, 'date')); - this.own(sync(this, 'currentDate', this._dailyTimeList, 'date')); - this.own(sync(this._dailyTimeWidget, 'selectedId', this._dailyTimeList, 'selectedId')); this.own(syncFrom(modelRegistry, 'timeEntryStore', this._daysInWeekList)); this.own(syncFrom(modelRegistry, 'timeEntryStore', this._dailyTimeWidget)); this.own(syncFrom(modelRegistry, 'taskStore', this._dailyTimeWidget)); - this.own(syncFrom(modelRegistry, 'timeEntryStore', this._dailyTimeList)); - this.own(syncFrom(modelRegistry, 'taskStore', this._dailyTimeList)); this.own(this._dailyTimeWidget.on('createTimeEntry', lang.hitch(this, '_createTimeEntry'))); this.own(this._dailyTimeWidget.on('updateTimeEntry', lang.hitch(this, '_updateTimeEntry'))); @@ -56,7 +51,7 @@ define([ .then(lang.hitch(this, function(result) { _.defer(lang.hitch(this, function() { // When an entry is added start editing it. - this._dailyTimeList.set("editingId", result.timeEntryId); + this._dailyTimeWidget.set("selectedId", result.timeEntryId); })); })); }, diff --git a/script/mytime/widget/DailyTimeList.js b/script/mytime/widget/DailyTimeList.js deleted file mode 100755 index 13403ff..0000000 --- a/script/mytime/widget/DailyTimeList.js +++ /dev/null @@ -1,267 +0,0 @@ -/** - * @license - * Copyright 2014 David Wolverton - * Available under MIT license - */ -define([ - "lodash", "dojo/_base/lang", "dojo/_base/declare", "dojo/when", - "dojo/dom-construct", "dojo/dom-class", "dojo/dom-attr", "dojo/on", "dojo/query", "dojo/Evented", "dojo/dom", - "dijit/_WidgetBase", "dijit/form/Textarea", "dijit/focus", - "mytime/widget/TaskPickerCombo", "mytime/widget/TaskDialog", - "mytime/model/TimeEntry", - "mytime/command/UpdateTimeEntryCommand", "mytime/command/UpdateTaskCommand", - "mytime/util/Colors", "mytime/util/whenAllPropertiesSet", "mytime/util/store/TransformingStoreView", - "mytime/util/store/StoreDrivenDom", "mytime/util/DateTimeUtil", "mytime/util/jira", - "dojo/text!mytime/widget/DailyTimeList/templates/entry.html", - "dojo/text!mytime/widget/DailyTimeList/templates/entry-edit.html" -], -function ( - _, lang, declare, when, - domConstruct, domClass, domAttr, on, query, Evented, dom, - _WidgetBase, Textarea, focusUtil, - TaskPickerCombo, TaskDialog, - TimeEntry, - UpdateTimeEntryCommand, UpdateTaskCommand, - Colors, whenAllPropertiesSet, TransformingStoreView, - StoreDrivenDom, DateTimeUtil, jira, - template, editTemplate) { - - /** - * - */ - return declare([_WidgetBase, Evented], { - - baseClass: "timelist", - - date: null, - timeEntryStore: null, - taskStore: null, - - selectedId: null, - editingId: null, - _editingStartData: null, - - _internalStore: null, - _list: null, - - _taskCombo: null, - _notesBox: null, - - buildRendering: function() { - this.inherited(arguments); - }, - - postCreate: function() { - var _this = this; - this.own( - whenAllPropertiesSet(this, ["date", "timeEntryStore", "taskStore"], lang.hitch(this, "_initialize")), - on(this.domNode, on.selector(".task, .note, .menu-button", "click"), function(event) { - // NOTE: for 'on' with selector, 'this' is the node identified by the selector. - _this._onEntryClick(event, this); - }), - on(document, 'mouseup', lang.hitch(this, '_onClickElsewhere')) - ); - }, - - _initialize: function() { - this._setupTaskCombo(); - this._setupNotesBox(); - this._internalStore = new TransformingStoreView({ - sourceStore: this.timeEntryStore, - sourceQuery: {date: this.date}, - transform: lang.hitch(this, function(input) { - var entry = new TimeEntry(input); - entry.selected = entry.id === this.selectedId; - entry.editing = entry.id === this.editingId; - return entry; - }) - }).getObservable(); - this._list = new StoreDrivenDom({ - store: this._internalStore, - queryOptions: {sort: [{attribute: "startHour"}]}, - renderNode: lang.hitch(this, "_renderEntry") - }); - - this._list.placeAt(this.domNode); - - this.own( - this.watch("date", lang.hitch(this, "_dateChanged")), - this.watch("editingId", lang.hitch(this, "_editingOrSelectedIdChanged")), - this.watch("selectedId", lang.hitch(this, "_editingOrSelectedIdChanged")) - ); - }, - - _setupTaskCombo: function() { - this._taskCombo = new TaskPickerCombo({ - store: this.taskStore - }); - this.own( - on(this._taskCombo, "change", lang.hitch(this, "_onTaskComboChange")) - ); - }, - - _setupNotesBox: function() { - this._notesBox = new Textarea(); - this.own( - on(this._notesBox, "change", lang.hitch(this, "_onNotesBoxChange")) - ); - }, - - _renderEntry: function(timeEntry) { - var task = null; - if (timeEntry.taskId) { - task = this.taskStore.get(timeEntry.taskId); - } - return this._renderEntryWithTask(timeEntry, task); - }, - - _renderEntryWithTask: function(timeEntry, task) { - var data = { - Colors: Colors, - timeEntryId: timeEntry.id, - taskId: "", - text: timeEntry.text || "", - duration: DateTimeUtil.duration(timeEntry), - code: "[ ]", - name: "No Task", - color: null, - selected: timeEntry.selected, - jiraLoggingUrl: "" - }; - if (task) { - data.taskId = task.id || ""; - data.code = task.code || ""; - data.name = task.name || ""; - data.color = task.color || null; - if (jira.isJiraIssueKey(task.code)) { - data.jiraLoggingUrl = jira.buildTimeLoggingLink(task.code, timeEntry); - } - } - if (timeEntry.editing) { - return this._renderEditingEntry(timeEntry, task, data); - } else { - var html = _.template(template, data); - return domConstruct.toDom(html); - } - }, - - _renderEditingEntry: function(timeEntry, task, data) { - var html = _.template(editTemplate, data); - var dom = domConstruct.toDom(html); - - this._editingStartData = { - taskId: task ? task.id : null, - text: timeEntry.text - }; - - var comboContainer = query(".task", dom)[0]; - this._taskCombo.set("task", task); - this._taskCombo.placeAt(comboContainer); - this._taskCombo.startup(); - - var noteContainer = query(".note", dom)[0]; - this._notesBox.set("value", timeEntry.text); - this._notesBox.placeAt(noteContainer); - this._notesBox.startup(); - - return dom; - }, - - _dateChanged: function() { - this._internalStore.set("sourceQuery", {date: this.date}); - }, - - _onEntryClick: function(event, node) { - var entryNode = this._getTimeEntryNodeContaining(node); - var entryId = domAttr.get(entryNode, "data-timeentry-id"); - var taskId = domAttr.get(entryNode, "data-task-id"); - - if (domClass.contains(node, 'task') || domClass.contains(node, 'note')) { - this.set("selectedId", entryId); - this.set("editingId", entryId); - } else if (domClass.contains(node, 'menu-button')) { - this._onMenuClick(node, entryId, taskId); - } - }, - - _getTimeEntryNodeContaining: function(node) { - do { - if (domClass.contains(node, 'timeentry')) { - return node; - } - node = node.parentNode; - } while (node); - return null; - }, - - _onMenuClick: function(buttonNode, entryId, taskId) { - if (!taskId) { - return; - } - when(this.taskStore.get(taskId), function(task) { - var dialog = new TaskDialog({value: task}); - dialog.showAndWaitForUser().then(function(task) { - dialog.destroy(); - new UpdateTaskCommand({task: task}).exec(); - }, function() { - dialog.destroy(); - }); - }); - }, - - _editingOrSelectedIdChanged: function(prop, prevValue, value) { - if (value !== prevValue) { - if (prevValue) { - this._internalStore.refreshItem(prevValue); - } - if (value) { - this._internalStore.refreshItem(value); - if (prop === "editingId") { - this._taskCombo.focusAndSelectAll(); - } - } - } - }, - - _onTaskComboChange: function() { - var task = this._taskCombo.get('task'); - var taskId = task ? task.id : null; - if (taskId !== this._editingStartData.taskId) { - this._editingStartData.taskId = taskId; - new UpdateTimeEntryCommand({timeEntry: { - id: this.editingId, - taskId: taskId - }}).exec(); - } - }, - - _onNotesBoxChange: function() { - var text = this._notesBox.get('value'); - if (text !== this._editingStartData.text) { - this._editingStartData.text = text; - new UpdateTimeEntryCommand({timeEntry: { - id: this.editingId, - text: text - }}).exec(); - } - }, - - /** - * Hide the editor when clicking outside this widget. - */ - _onClickElsewhere: function(event) { - if (!this.editingId) { - return; - } - if (_.contains(focusUtil.activeStack, this._taskCombo.id) || - _.contains(focusUtil.activeStack, this._notesBox.id)) { - return; - } - if (event.target === this.domNode || dom.isDescendant(event.target, this.domNode)) { - return; - } - this.set('editingId', null); - } - - }); -}); \ No newline at end of file diff --git a/script/mytime/widget/DailyTimeList/templates/entry-edit.html b/script/mytime/widget/DailyTimeList/templates/entry-edit.html deleted file mode 100755 index 270377a..0000000 --- a/script/mytime/widget/DailyTimeList/templates/entry-edit.html +++ /dev/null @@ -1,19 +0,0 @@ -
- - - - - <% if (taskId) { %> - - <% } %> - - - <% if (jiraLoggingUrl) { %> - - - - <% } %> - -
\ No newline at end of file diff --git a/script/mytime/widget/DailyTimeList/templates/entry.html b/script/mytime/widget/DailyTimeList/templates/entry.html deleted file mode 100755 index 2083542..0000000 --- a/script/mytime/widget/DailyTimeList/templates/entry.html +++ /dev/null @@ -1,19 +0,0 @@ -
- - <%- code %> - <%- name %> - - <%- text %> - - <% if (taskId) { %> - - <% } %> - <% if (jiraLoggingUrl) { %> - - - - <% } %> - -
\ No newline at end of file diff --git a/script/mytime/widget/DailyTimeWidget.js b/script/mytime/widget/DailyTimeWidget.js index a4e18a7..bea143f 100755 --- a/script/mytime/widget/DailyTimeWidget.js +++ b/script/mytime/widget/DailyTimeWidget.js @@ -34,7 +34,7 @@ function ( */ date: null, - startHour: 6, + startHour: 0, endHour: 23, @@ -45,8 +45,8 @@ function ( selectedId: null, - nowHour: 0, - endOfDayHour: 0, + nowHour: -1, + endOfDayHour: -1, // TODO update this according to hours remaining _internalStore: null, @@ -78,6 +78,8 @@ function ( this.own( this._view.on("endDrag", lang.hitch(this, "_endDragListener")), this._view.on("click", lang.hitch(this, "_clickListener")), + this._view.on("prevDay", lang.hitch(this, "addDays", -1)), + this._view.on("nextDay", lang.hitch(this, "addDays", +1)), this.watch("date", lang.hitch(this, "_updateNowHour")) ); @@ -104,6 +106,8 @@ function ( var entry = this._findEntryContainingHour(hour); if (entry && entry.id !== this.selectedId) { this.set("selectedId", entry.id); + } else if (!entry) { + this.set("selectedId", null); } }, @@ -212,6 +216,18 @@ function ( } else { this.set("nowHour", -1); } + }, + + /** + * Adjust the selectedDate by a certain number of days. + * @param daysToAdd number of days to add + or - + */ + addDays: function(daysToAdd) { + var date = DateTimeUtil.convertDateStringToDateObject(this.get('date')); + var millis = date.valueOf(); + millis += 86400000 * daysToAdd; + date.setTime(millis); + this.set('date', DateTimeUtil.convertDateObjectToDateString(date)); } }); diff --git a/script/mytime/widget/DailyTimeWidget/DailyTimeWidgetStore.js b/script/mytime/widget/DailyTimeWidget/DailyTimeWidgetStore.js index a30fa9e..7155d82 100755 --- a/script/mytime/widget/DailyTimeWidget/DailyTimeWidgetStore.js +++ b/script/mytime/widget/DailyTimeWidget/DailyTimeWidgetStore.js @@ -48,7 +48,7 @@ define([ var task = this.taskStore.get(timeEntry.taskId); if (task) { timeEntry.color = task.color; - timeEntry.code = task.code; + timeEntry.description = task.description; } } return timeEntry; diff --git a/script/mytime/widget/DailyTimeWidget/DailyTimeWidgetView.js b/script/mytime/widget/DailyTimeWidget/DailyTimeWidgetView.js index 35cefff..9fd0107 100755 --- a/script/mytime/widget/DailyTimeWidget/DailyTimeWidgetView.js +++ b/script/mytime/widget/DailyTimeWidget/DailyTimeWidgetView.js @@ -270,7 +270,7 @@ function (declare, } i++; } - this._setTextOnTimeBars(timeBars, timeEntry.code); + this._setTextOnTimeBars(timeBars, timeEntry.description); }, _buildTimeBarsForTimeEntry: function(timeEntry) { @@ -280,7 +280,7 @@ function (declare, timeBars.push(timebar); this._placeTimeBar(timebar, slot.hour); }, this); - this._setTextOnTimeBars(timeBars, timeEntry.code); + this._setTextOnTimeBars(timeBars, timeEntry.description); }, _placeTimeBar: function(timebar, hour) { @@ -372,6 +372,14 @@ function (declare, markNode.parentNode.removeChild(markNode); } } + }, + + _clickPrevDay: function() { + this.emit('prevDay') + }, + + _clickNextDay: function() { + this.emit('nextDay') } }); }); \ No newline at end of file diff --git a/script/mytime/widget/JiraPickerCombo.js b/script/mytime/widget/JiraPickerCombo.js new file mode 100755 index 0000000..eb1b81e --- /dev/null +++ b/script/mytime/widget/JiraPickerCombo.js @@ -0,0 +1,53 @@ +/** + * @license + * Copyright 2014 David Wolverton + * Available under MIT license + */ +define([ + "lodash", "dojo/_base/lang", "dojo/_base/declare", + "dijit/form/ComboBox", + "mytime/command/CreateTaskCommand", "mytime/model/Task", + "mytime/util/Colors", + "mytime/widget/TaskPickerComboStore" +], +function ( + _, lang, declare, + ComboBox, + CreateTaskCommand, Task, + Colors, + TaskPickerComboStore + ) { + return declare([ComboBox], { + + searchAttr: "_searchText", + + labelType: "html", + + queryExpr: "${0}", + + constructor: function() { + this.baseClass += " taskpicker"; + }, + + _getTaskAttr: function() { + return this.get("jiraIssue"); + }, + + _setTaskAttr: function(task) { + if (task) { + task = new Task(task); + task._searchText = task.description; + } + this.set("jiraIssue", task); + }, + + labelFunc: function(item, store) { + return _.escape(item.description); + }, + + focusAndSelectAll: function() { + this.focus(); + this.focusNode.select(); + } + }); +}); \ No newline at end of file diff --git a/script/mytime/widget/TaskDialog.js b/script/mytime/widget/TaskDialog.js deleted file mode 100755 index fc0e3a3..0000000 --- a/script/mytime/widget/TaskDialog.js +++ /dev/null @@ -1,67 +0,0 @@ -define([ - 'dojo/_base/lang', 'dojo/_base/declare', 'dojo/Deferred', - 'dijit/Dialog', - 'mytime/widget/TaskForm' -], function(lang, declare, Deferred, Dialog, TaskForm) { - return declare([Dialog], { - - form: null, - - _formDeferred: null, - - /** - * Show the dialog and return a promise that will be resolved when the user clicks OK or rejected when the user - * clicks Cancel. - * @param value - * @returns {Deferred.promise|*|dojo.Deferred.promise} - */ - showAndWaitForUser: function(value) { - if (value) { - this.set('value', value); - } - this.show(); - this._formDeferred = new Deferred(); - - return this._formDeferred.promise; - }, - - constructor: function() { - this.form = new TaskForm(); - }, - - postCreate: function() { - this.inherited(arguments); - this.set('content', this.form); - this.form.on('submit', lang.hitch(this, '_submit')); - this.form.on('cancel', lang.hitch(this, '_cancel')); - }, - - _setValueAttr: function(value) { - this.set('title', 'Task ' + value.code); - this.form.set('value', value); - }, - - _getValueAttr: function() { - return this.form.get('value'); - }, - - _submit: function(value) { - if (this._formDeferred) { - this._formDeferred.resolve(value); - this._formDeferred = null; - } - // NOTE: hide is not needed because the Dialog code seems to handle it automatically. - }, - - _cancel: function() { - this.hide(); - }, - - onHide: function() { - if (this._formDeferred) { - this._formDeferred.reject('Canceled'); - this._formDeferred = null; - } - } - }); -}); \ No newline at end of file diff --git a/script/mytime/widget/TaskForm.js b/script/mytime/widget/TaskForm.js deleted file mode 100755 index f30763e..0000000 --- a/script/mytime/widget/TaskForm.js +++ /dev/null @@ -1,50 +0,0 @@ -define([ - 'lodash', - 'dojo/_base/lang', 'dojo/_base/declare', - 'dijit/_WidgetBase', 'dijit/_TemplatedMixin', 'dijit/_WidgetsInTemplateMixin', - 'mytime/model/Task', - 'dojo/text!./TaskForm/TaskFormContent.html', - /* widgets in template */ - 'dijit/form/Form', 'dijit/form/TextBox', 'dijit/form/Button' -], function ( - _, - lang, declare, - _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, - Task, - TaskFormContent) { - - return declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], { - - baseClass: 'task-form', - - templateString: TaskFormContent, - - /** - * Attach Point - */ - form: null, - - value: null, - - _setValueAttr: function(value) { - this.value = value; - this.form.set('value', value); - }, - - _getValueAttr: function() { - var props = lang.mixin({}, this.value, this.form.get('value')); - return new Task(props); - }, - - postCreate: function() { - this.form.onSubmit = lang.hitch(this, function() { - this.emit('submit', this.get('value')); - return false; - }); - }, - - cancel: function() { - this.emit('cancel'); - } - }); -}); \ No newline at end of file diff --git a/script/mytime/widget/TaskForm/TaskFormContent.html b/script/mytime/widget/TaskForm/TaskFormContent.html deleted file mode 100755 index 2758466..0000000 --- a/script/mytime/widget/TaskForm/TaskFormContent.html +++ /dev/null @@ -1,20 +0,0 @@ -
-
-
- - -
-
- - -
-
- - -
-
- - Cancel -
-
-
\ No newline at end of file diff --git a/script/mytime/widget/TaskPickerCombo.js b/script/mytime/widget/TaskPickerCombo.js index 295a445..bfecdee 100755 --- a/script/mytime/widget/TaskPickerCombo.js +++ b/script/mytime/widget/TaskPickerCombo.js @@ -4,14 +4,14 @@ * Available under MIT license */ define([ - "lodash", "dojo/_base/lang", "dojo/_base/declare", + "lodash", "dojo/_base/lang", "dojo/_base/declare", "dojo/on", "dijit/form/ComboBox", "mytime/command/CreateTaskCommand", "mytime/model/Task", "mytime/util/Colors", "mytime/widget/TaskPickerComboStore" ], function ( - _, lang, declare, + _, lang, declare, on, ComboBox, CreateTaskCommand, Task, Colors, @@ -25,19 +25,26 @@ function ( queryExpr: "${0}", + _lastTask: null, + constructor: function() { this.baseClass += " taskpicker"; }, _getTaskAttr: function() { - return this.get("item"); + var task = this.get("item"); + if (!task) { + task = this._parseStringToTask(this.get('value')); + } + return task; }, _setTaskAttr: function(task) { if (task) { task = new Task(task); - task._searchText = Task.getDisplayText(task); + task._searchText = task.description; } + this._lastTask = task; this.set("item", task); }, @@ -50,14 +57,38 @@ function ( _handleOnChange: function(newStringValue) { this.inherited(arguments); - if (!this.item && newStringValue) { - var task = this._parseStringToTask(newStringValue); - if (task) { - new CreateTaskCommand({task: task}).exec().then(lang.hitch(this, function(result) { - this.set("task", result.task); - })); + //if (this.item && this.item.description != newStringValue) { + // this.set('value', this.item.description); + //} + }, + + postCreate: function() { + this.inherited(arguments); + this.own( + on(this, "change", lang.hitch(this, '_checkForChange')) + ); + }, + + _checkForChange: function() { + var task = this.get('task'); + var taskId = task ? task.id : null; + var taskDescription = task ? task.description : null; + if (this._lastTask) { + if (this._lastTask.id !== taskId || this._lastTask.description !== taskDescription) { + this._lastTask = task; + this.onUserchange(task); + } + } else { + if (taskDescription) { + this._lastTask = task; + this.onUserchange(task); } } + + var expectedDescription = task ? task.description : ''; + if (this.get('value') !== expectedDescription) { + this.set('task', task); + } }, _parseStringToTask: function(string) { @@ -67,31 +98,22 @@ function ( } var task = { - code: string + description: string }; - var firstSpace = string.indexOf(' '); - if (firstSpace > -1) { - task.code = string.substring(0, firstSpace); - task.name = string.substring(firstSpace + 1).trim(); - if (task.name.length < 1) { - delete task.name; - } - } - return this._isValidCode(task.code) ? task : null; + return this._isValidDescription(task.description) ? task : null; }, - _isValidCode: function(code) { - return code && code.length > 1; + _isValidDescription: function(description) { + return description && description.length > 1; }, - labelFunc: function(item, store) { - return '' + - _.escape(item.code) + ' ' + _.escape(item.name || "") + ''; - }, + labelAttr: "description", focusAndSelectAll: function() { this.focus(); this.focusNode.select(); - } + }, + + onUserchange: function(task) {} }); }); \ No newline at end of file diff --git a/script/mytime/widget/TaskPickerComboStore.js b/script/mytime/widget/TaskPickerComboStore.js index 21707dd..dc8e40e 100755 --- a/script/mytime/widget/TaskPickerComboStore.js +++ b/script/mytime/widget/TaskPickerComboStore.js @@ -41,7 +41,7 @@ function ( var task = this.store.get.apply(this.store, arguments); if (task) { task = new Task(task); - task._searchText = Task.getDisplayText(task); + task._searchText = task.description; } return task; }, @@ -53,11 +53,9 @@ function ( if (queryString) { var escapedQueryString = this._escapeRegExp(queryString); var beginningRegExp = new RegExp("(^|\\b)" + escapedQueryString, "i"); - var endingRegExp = new RegExp(escapedQueryString + "$", "i"); rawQuery = function(task) { - return ( task.code && ( beginningRegExp.test(task.code) || endingRegExp.test(task.code) ) ) - || ( task.name && beginningRegExp.test(task.name) ); + return task.description && beginningRegExp.test(task.description); }; this._beginningRegExp = beginningRegExp; @@ -70,7 +68,7 @@ function ( this._queryString = queryString; var options = { -// sort: [{attribute: 'code', descending: true}] +// sort: [{attribute: 'description', descending: true}] }; var rawResults = this.store.query(rawQuery, options); @@ -94,23 +92,18 @@ function ( if (this._beginningRegExp) { task._searchText = this._buildSearchText(task); } else { - task._searchText = Task.getDisplayText(task); + task._searchText = task.description } return task; }, _buildSearchText: function(task) { - var firstInCode = task.code && task.code.search(this._beginningRegExp); - if (firstInCode === 0) { - return Task.getDisplayText(task); + var locationInDescription = task.description && task.description.search(this._beginningRegExp); + if (locationInDescription === 0) { + return task.description; } else { - var firstInName = task.name && task.name.search(this._beginningRegExp); - if (firstInName === 0) { - return task.name + " ~ " + task.code; - } else { - return this._queryString + " ~ " + Task.getDisplayText(task); - } + return this._queryString + " ~ " + task.description; } }, diff --git a/script/mytime/widget/TimeEntryDetails.js b/script/mytime/widget/TimeEntryDetails.js new file mode 100755 index 0000000..31edd5c --- /dev/null +++ b/script/mytime/widget/TimeEntryDetails.js @@ -0,0 +1,229 @@ +/** + * @license + * Copyright 2014 David Wolverton + * Available under MIT license + */ +define([ + "lodash", "dojo/_base/lang", "dojo/_base/declare", "dojo/when", "dojo/Stateful", "dojo/Evented", + "dijit/_WidgetBase", + "mytime/widget/TimeEntryDetails/TimeEntryDetailsView", + "mytime/store/JiraPicklistStore", + "mytime/command/UpdateTimeEntryCommand", + "mytime/command/CreateTaskCommand", "mytime/command/UpdateTaskCommand", + "mytime/util/whenAllPropertiesSet", "mytime/util/syncFrom" +], +function ( + _, lang, declare, when, Stateful, Evented, + _WidgetBase, + TimeEntryDetailsView, + JiraPicklistStore, + UpdateTimeEntryCommand, CreateTaskCommand, UpdateTaskCommand, + whenAllPropertiesSet, syncFrom) { + + + /** + * The slide out details entry/task details pane + */ + return declare([_WidgetBase, Evented], { + + timeEntryStore: null, + taskStore: null, + jiraStore: new JiraPicklistStore(), + + selectedId: null, + + currentTimeEntry: null, + currentTask: null, + + _model: null, + _view: null, + + constructor: function() { + this._model = new Stateful({ + task: null, + jiraKey: null + }); + + this._view = new TimeEntryDetailsView({ + model: this._model, + jiraStore: this.jiraStore + }); + syncFrom(this, 'taskStore', this._view); + }, + + buildRendering: function() { + this.domNode = this._view.domNode; + }, + + postCreate: function() { + this.own( + whenAllPropertiesSet(this, ["timeEntryStore", "taskStore"], lang.hitch(this, "_initialize")) + ); + }, + + _initialize: function() { + this.own( + this.watch("selectedId", lang.hitch(this, "_selectedIdChanged")), + this._view.on("taskSelected", lang.hitch(this, "_taskSelected")), + this._view.on("jiraSelected", lang.hitch(this, "_jiraSelected")) + ); + this._selectedIdChanged(null, null, this.selectedId); + }, + + _selectedIdChanged: function(prop, prevValue, value) { + if (value !== prevValue) { + if (!value) { + this._view.hide(); + } else { + this._fillInFromId(value); + this._view.show(); + } + } + }, + + _fillInFromId: function(timeEntryId) { + when(this.timeEntryStore.get(timeEntryId), lang.hitch(this, function(timeEntry) { + if (timeEntry.taskId) { + when(this.taskStore.get(timeEntry.taskId), lang.hitch(this, function (task) { + this._fillIn(timeEntry, task); + }), lang.hitch(this._view, 'hide')); + } else { + this._fillIn(timeEntry, null); + } + }), lang.hitch(this._view, 'hide')); + }, + + _fillIn: function(timeEntry, task) { + // TODO watch for changes to this time entry and task + this.currentTimeEntry = timeEntry; + this.currentTask = task; + + this._model.set('task', task); + + var jiraIntegration = this._getIntegrationOfType(task, 'jira'); + if (jiraIntegration) { + this._model.set('jiraKey', jiraIntegration.id); + } else { + this._model.set('jiraKey', null); + } + }, + + _taskSelected: function(task) { + var taskId = task ? task.id : null; + if (!task) { + // unset task from entry + this._updateEntry({ + taskId: null + }); + } else if (task.id) { + // existing task + if (task.id !== this.currentTimeEntry.taskId) { + this._updateEntry({ + taskId: task.id + }); + } + } else if (task.description) { + // new task + this._createTask({ + description: task.description + }).then(lang.hitch(this, function(result) { + this._updateEntry({ + taskId: result.taskId + }); + })); + } + }, + + _jiraSelected: function() { + + }, + + _onJiraKeyChange: function() { + var item = this.jiraKeyInput.get('item'); + var key = item ? item.id : null; + + var task = this.currentTask; + var entry = this.currentTimeEntry; + if (key && !task) { + task = { + description: item.label + }; + } + + if (!key) { + if (!this._removeIterationOfType(task, 'jira')) { + return; + } + } else { + var integration = this._getOrAddIntegrationOfType(task, 'jira'); + if (integration.id === key) { + return; + } + integration.id = key; + } + + this._createOrUpdateTask(task).then(lang.hitch(this, function(result) { + var task = result.task; + var change = false; + if (entry.taskId !== task.id) { + entry.taskId = task.id; + change = true; + } + // TODO here we need to update associated entries at some point + + if (change) { + this._updateEntry(entry); + } + })); + }, + + _getOrAddIntegrationOfType: function(object, type) { + object.integrations = object.integrations || []; + var integration = _.find(object.integrations, {type: type}); + if (!integration) { + integration = { + type: type + }; + object.integrations.push(integration); + } + return integration; + }, + + _getIntegrationOfType: function(object, type) { + return _.find(object ? object.integrations : null, {type: type}); + }, + + /** + * Return true if found and removed. + */ + _removeIterationOfType: function(object, type) { + if (!object) { + return false; + } + var index = _.findIndex(object.integrations, {type: type}); + if (index != -1) { + object.integrations.splice(index, 1); + return true; + } + return false; + }, + + _createOrUpdateTask: function(task) { + if (task.id) { + return new UpdateTaskCommand({task: task}).exec(); + } else { + return new CreateTaskCommand({task: task}).exec(); + } + }, + + _updateEntry: function(entry) { + entry = lang.mixin({id: this.currentTimeEntry.id}, entry); + return new UpdateTimeEntryCommand({timeEntry: entry}).exec(); + }, + + _createTask: function(task) { + return new CreateTaskCommand({task: task}).exec(); + } + + }); +}); \ No newline at end of file diff --git a/script/mytime/widget/TimeEntryDetails/TimeEntryDetailsView.js b/script/mytime/widget/TimeEntryDetails/TimeEntryDetailsView.js new file mode 100755 index 0000000..24e24f2 --- /dev/null +++ b/script/mytime/widget/TimeEntryDetails/TimeEntryDetailsView.js @@ -0,0 +1,101 @@ +/** + * @license + * Copyright 2014 David Wolverton + * Available under MIT license + */ +define([ + "lodash", "dojo/_base/lang", "dojo/_base/declare", + "dojo/dom-construct", "dojo/dom-class", "dojo/dom-attr", "dojo/on", "dojo/query", "dojo/Evented", "dojo/dom", + "dijit/_WidgetBase", "dijit/_TemplatedMixin", "dijit/_WidgetsInTemplateMixin", + "dijit/form/Textarea", "dijit/form/FilteringSelect", "dijit/focus", + "mytime/util/syncFrom", "mytime/util/whenAllPropertiesSet", + "mytime/widget/TaskPickerCombo", + "dojo/text!mytime/widget/TimeEntryDetails/templates/TimeEntryDetails.html" +], +function ( + _, lang, declare, + domConstruct, domClass, domAttr, on, query, Evented, dom, + _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, + Textarea, FilteringSelect, focusUtil, + syncFrom, whenAllPropertiesSet, + TaskPickerCombo, + template) { + + + /** + * The slide out details entry/task details pane + * + * @emit taskSelected {id: string, description: string} + */ + return declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, Evented], { + + templateString: template, + + // in template + descriptionNode: null, + jiraKeyNode: null, + + descriptionInput: null, + jiraKeyInput: null, + + model: null, + + _lastSetJiraKey: null, + + postCreate: function() { + this.own( + whenAllPropertiesSet(this, ["taskStore"], lang.hitch(this, "_initialize")) + ); + }, + + _initialize: function() { + this.descriptionInput = new TaskPickerCombo({ + store: this.taskStore + }); + this.descriptionInput.placeAt(this.descriptionNode); + + this.jiraKeyInput = new FilteringSelect({ + store: this.jiraStore, + searchAttr: 'label', + queryExpr: "${0}" + }); + this.jiraKeyInput.placeAt(this.jiraKeyNode); + + window.tl = this.descriptionInput; + window.jl = this.jiraKeyInput; + + this.own( + on(this.descriptionInput, "userchange", lang.hitch(this, '_onDescriptionChange') ), + on(this.jiraKeyInput, "change", lang.hitch(this, "_onJiraKeyChange")), + this.model.watch('task', lang.hitch(this, "_incomingTaskChange")) + ); + + syncFrom(this.model, "jiraKey", this.jiraKeyInput, "value"); + + }, + + show: function() { + domClass.toggle(this.domNode, 'open', true); + }, + + hide: function() { + domClass.toggle(this.domNode, 'open', false); + }, + + _onDescriptionChange: function(task) { + on.emit(this, "taskSelected", task); + }, + + _onJiraKeyChange: function() { + var jiraKey = this.jiraKeyInput.get('value'); + if (jiraKey !== this.model.get('jiraKey')) { + on.emit(this, "jiraSelected", jiraKey); + } + }, + + _incomingTaskChange: function(prop, prevValue, value) { + this.descriptionInput.set('task', value); + } + + }); +}); \ No newline at end of file diff --git a/script/mytime/widget/TimeEntryDetails/templates/TimeEntryDetails.html b/script/mytime/widget/TimeEntryDetails/templates/TimeEntryDetails.html new file mode 100755 index 0000000..f411df2 --- /dev/null +++ b/script/mytime/widget/TimeEntryDetails/templates/TimeEntryDetails.html @@ -0,0 +1,50 @@ +
+
+ + + + +
+ + +
\ No newline at end of file From 77ad54216c4adf6b49f9fb2de8d8c3219055561f Mon Sep 17 00:00:00 2001 From: David Wolverton Date: Sat, 13 Jun 2015 16:03:20 -0400 Subject: [PATCH 03/12] bigger main view --- .../widget/DailyTimeWidget/DailyTimeWidgetView.js | 4 +++- styles.css | 14 +++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/script/mytime/widget/DailyTimeWidget/DailyTimeWidgetView.js b/script/mytime/widget/DailyTimeWidget/DailyTimeWidgetView.js index 9fd0107..1fb0aef 100755 --- a/script/mytime/widget/DailyTimeWidget/DailyTimeWidgetView.js +++ b/script/mytime/widget/DailyTimeWidget/DailyTimeWidgetView.js @@ -75,7 +75,9 @@ function (declare, }, _getLabelForHour: function(hour) { - if (hour < 12) { + if (hour == 0) { + return "12:00 am"; + } else if (hour < 12) { return hour + ":00 am"; } else if (hour == 12) { return hour + ":00 pm"; diff --git a/styles.css b/styles.css index 9b4e019..62d561e 100755 --- a/styles.css +++ b/styles.css @@ -112,7 +112,7 @@ div.dayslist { div.timegrid { - width: 300px; + width: 600px; font-family: sans-serif; color: #333; } @@ -145,6 +145,10 @@ div.timegrid { text-align: right; width: 4.2em; } + + .timegrid tbody tr { + height: 40px; + } .timegrid th, .timegrid td { border: 1px solid black; @@ -224,14 +228,14 @@ div.timegrid { .timegrid .start { border-left-style: solid; - border-top-left-radius: .5em; - border-bottom-left-radius: .5em; + border-top-left-radius: 1em; + border-bottom-left-radius: 1em; } .timegrid .end { border-right-style: solid; - border-top-right-radius: .5em; - border-bottom-right-radius: .5em; + border-top-right-radius: 1em; + border-bottom-right-radius: 1em; } .timegrid .time-bar.selected { From f847dfc0bb1302305521c9769e29d87ab2a6eadf Mon Sep 17 00:00:00 2001 From: David Wolverton Date: Sat, 13 Jun 2015 22:31:43 -0400 Subject: [PATCH 04/12] time entry details pane --- script/mytime/main.js | 2 + script/mytime/store/DummyJiraPicklistStore.js | 45 ++++++++++++++++ script/mytime/view/TimeEntryPane.html | 5 +- script/mytime/view/TimeEntryPane.js | 7 ++- .../DailyTimeWidget/templates/grid.html | 8 ++- script/mytime/widget/TimeEntryDetails.js | 2 +- .../TimeEntryDetails/TimeEntryDetailsView.js | 4 +- .../templates/TimeEntryDetails.html | 54 +++---------------- styles.css | 30 ++++++++--- 9 files changed, 97 insertions(+), 60 deletions(-) create mode 100755 script/mytime/store/DummyJiraPicklistStore.js diff --git a/script/mytime/main.js b/script/mytime/main.js index b262156..eb6738e 100755 --- a/script/mytime/main.js +++ b/script/mytime/main.js @@ -32,4 +32,6 @@ define([ new JiraController({ requestQueue: requestQueue }); //mockData(); + window.taskStore = modelRegistry.get('taskStore'); + window.timeEntryStore = modelRegistry.get('timeEntryStore'); }); \ No newline at end of file diff --git a/script/mytime/store/DummyJiraPicklistStore.js b/script/mytime/store/DummyJiraPicklistStore.js new file mode 100755 index 0000000..75de5bd --- /dev/null +++ b/script/mytime/store/DummyJiraPicklistStore.js @@ -0,0 +1,45 @@ +/** + * @license + * Copyright 2014 David Wolverton + * Available under MIT license + */ +define(["lodash", "dojo/_base/declare", "dojo/_base/lang", "dojo/Deferred", "mytime/command/GetJiraPickListCommand"], +function (_, declare, lang, Deferred, GetJiraPickListCommand) { + return declare([], { + + get: function(id) { + return { + id: id, + description: 'Hello', + label: id + } + }, + + query: function(query) { + var id = this._normalizeQuery(query); + if (!id) { + id = 'NONE' + } + + return [ + this.get(id) + ] + }, + + _normalizeQuery: function(query) { + if (!query) { + return null; + } else if (typeof query === 'string') { + return query; + } else if (query.label) { + return this._normalizeQuery(query.label.toString()); + } else { + return null; + } + }, + + getIdentity: function(object) { + return object ? object.id : null; + } + }); +}); \ No newline at end of file diff --git a/script/mytime/view/TimeEntryPane.html b/script/mytime/view/TimeEntryPane.html index 024457c..75df8de 100755 --- a/script/mytime/view/TimeEntryPane.html +++ b/script/mytime/view/TimeEntryPane.html @@ -1,6 +1,7 @@
-
+
+ +
\ No newline at end of file diff --git a/script/mytime/view/TimeEntryPane.js b/script/mytime/view/TimeEntryPane.js index a16aeca..e0cdb8a 100755 --- a/script/mytime/view/TimeEntryPane.js +++ b/script/mytime/view/TimeEntryPane.js @@ -13,7 +13,7 @@ define([ 'dojox/mvc/sync', 'dojo/text!./TimeEntryPane.html', /* In template: */ - 'mytime/widget/DaysInWeekList', 'mytime/widget/DailyTimeWidget' + 'mytime/widget/DaysInWeekList', 'mytime/widget/DailyTimeWidget', 'mytime/widget/TimeEntryDetails' ], function ( _, lang, declare, _WidgetBase, @@ -27,19 +27,24 @@ define([ return declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], { templateString: template, + baseClass: 'time-entry-pane', _daysInWeekList: null, _dailyTimeWidget: null, + _timeEntryDetails: null, currentDate: DateTimeUtil.getCurrentDate(), postCreate: function() { this.own(sync(this, 'currentDate', this._daysInWeekList, 'selectedDate')); this.own(sync(this, 'currentDate', this._dailyTimeWidget, 'date')); + this.own(syncFrom(this._dailyTimeWidget, 'selectedId', this._timeEntryDetails)); this.own(syncFrom(modelRegistry, 'timeEntryStore', this._daysInWeekList)); this.own(syncFrom(modelRegistry, 'timeEntryStore', this._dailyTimeWidget)); this.own(syncFrom(modelRegistry, 'taskStore', this._dailyTimeWidget)); + this.own(syncFrom(modelRegistry, 'timeEntryStore', this._timeEntryDetails)); + this.own(syncFrom(modelRegistry, 'taskStore', this._timeEntryDetails)); this.own(this._dailyTimeWidget.on('createTimeEntry', lang.hitch(this, '_createTimeEntry'))); this.own(this._dailyTimeWidget.on('updateTimeEntry', lang.hitch(this, '_updateTimeEntry'))); diff --git a/script/mytime/widget/DailyTimeWidget/templates/grid.html b/script/mytime/widget/DailyTimeWidget/templates/grid.html index 4234626..6649858 100755 --- a/script/mytime/widget/DailyTimeWidget/templates/grid.html +++ b/script/mytime/widget/DailyTimeWidget/templates/grid.html @@ -6,7 +6,11 @@ Weekday, 00 Month - - +
+ + + +
+
\ No newline at end of file diff --git a/script/mytime/widget/TimeEntryDetails.js b/script/mytime/widget/TimeEntryDetails.js index 31edd5c..e30928e 100755 --- a/script/mytime/widget/TimeEntryDetails.js +++ b/script/mytime/widget/TimeEntryDetails.js @@ -7,7 +7,7 @@ define([ "lodash", "dojo/_base/lang", "dojo/_base/declare", "dojo/when", "dojo/Stateful", "dojo/Evented", "dijit/_WidgetBase", "mytime/widget/TimeEntryDetails/TimeEntryDetailsView", - "mytime/store/JiraPicklistStore", + "mytime/store/DummyJiraPicklistStore", "mytime/command/UpdateTimeEntryCommand", "mytime/command/CreateTaskCommand", "mytime/command/UpdateTaskCommand", "mytime/util/whenAllPropertiesSet", "mytime/util/syncFrom" diff --git a/script/mytime/widget/TimeEntryDetails/TimeEntryDetailsView.js b/script/mytime/widget/TimeEntryDetails/TimeEntryDetailsView.js index 24e24f2..29d38a8 100755 --- a/script/mytime/widget/TimeEntryDetails/TimeEntryDetailsView.js +++ b/script/mytime/widget/TimeEntryDetails/TimeEntryDetailsView.js @@ -10,7 +10,9 @@ define([ "dijit/form/Textarea", "dijit/form/FilteringSelect", "dijit/focus", "mytime/util/syncFrom", "mytime/util/whenAllPropertiesSet", "mytime/widget/TaskPickerCombo", - "dojo/text!mytime/widget/TimeEntryDetails/templates/TimeEntryDetails.html" + "dojo/text!mytime/widget/TimeEntryDetails/templates/TimeEntryDetails.html", + /* Widgets in Template */ + "dijit/form/Form" ], function ( _, lang, declare, diff --git a/script/mytime/widget/TimeEntryDetails/templates/TimeEntryDetails.html b/script/mytime/widget/TimeEntryDetails/templates/TimeEntryDetails.html index f411df2..58e199f 100755 --- a/script/mytime/widget/TimeEntryDetails/templates/TimeEntryDetails.html +++ b/script/mytime/widget/TimeEntryDetails/templates/TimeEntryDetails.html @@ -1,50 +1,10 @@ -
-
- - - - -
-