├── logs
└── .empty
├── config
├── Seeds
│ └── empty
├── features.php
├── plugins.php
├── Migrations
│ ├── 20210316024149_UserSpecificProjectSlug.php
│ ├── 20210226033714_RenameTasksProjectSectionId.php
│ ├── 20241022042500_AddContentToFeedItems.php
│ ├── 20210915012937_ConvertCalendarItemsHtmlLinkToText.php
│ ├── 20241126033547_AddFaviconToFeeds.php
│ ├── 20221030031829_AddDeletedToTasks.php
│ ├── 20241103040408_AddExpandedToFeedCategoriesTable.php
│ ├── 20241110175742_AddAuthorToFeedItems.php
│ ├── 20210215044003_AddEveningToTasks.php
│ ├── 20210825015018_AddExpirationToCalendarSubscription.php
│ ├── 20240518035817_AddResourceIdToCalendarSubscriptions.php
│ ├── 20241112035515_AddDefaultAliasToFeedsTable.php
│ ├── 20210322024423_AddThemeToUser.php
│ ├── 20210728025420_AddDisplayNameToCalendarProvider.php
│ ├── 20240509041300_AddSyncedToCalendarSources.php
│ ├── 20210228192141_FixActionOnTasksSectionId.php
│ ├── 20241007030938_ExpandFeedItems.php
│ ├── 20241207223935_AddUnreadItemCountToFeedSubscriptions.php
│ └── 20220530022319_CreateApiTokens.php
├── schema
│ ├── i18n.sql
│ └── sessions.sql
└── bootstrap_cli.php
├── webroot
├── js
│ └── .gitkeep
├── favicon.ico
├── favicon.png
├── img
│ ├── cake-logo.png
│ ├── cake.icon.png
│ ├── cake.power.gif
│ ├── docket-logo.png
│ ├── docket-logo.svg
│ └── docket-logo-translucent.svg
├── font
│ ├── cakedingbats-webfont.eot
│ ├── cakedingbats-webfont.ttf
│ ├── cakedingbats-webfont.woff
│ └── cakedingbats-webfont.woff2
└── .htaccess
├── src
├── Model
│ ├── Behavior
│ │ └── .gitkeep
│ └── Entity
│ │ ├── SavedFeedItem.php
│ │ └── ApiToken.php
├── Policy
│ ├── ApiTokensTablePolicy.php
│ ├── UserPolicy.php
│ └── ApiTokenPolicy.php
├── Middleware
│ └── ApiCsrfProtectionMiddleware.php
├── Identifier
│ └── ApiTokenIdentifier.php
└── View
│ └── AppView.php
├── .yarnrc.yml
├── tests
├── js
│ ├── __mocks__
│ │ └── styleMock.js
│ ├── setup.ts
│ └── fixtures.ts
├── Fixture
│ ├── ApiTokensFixture.php
│ ├── LabelsTasksFixture.php
│ ├── google-auth.json
│ └── vcr
│ │ ├── controller_calendarsources_delete.yml
│ │ ├── googleoauth_callback_invalid.yml
│ │ └── controller_calendarsources_add_auth_fail.yml
└── Acceptance
│ └── LoginTest.php
├── flutterapp
├── ios
│ ├── Runner
│ │ ├── Runner-Bridging-Header.h
│ │ ├── Assets.xcassets
│ │ │ ├── LaunchImage.imageset
│ │ │ │ ├── LaunchImage.png
│ │ │ │ ├── LaunchImage@2x.png
│ │ │ │ ├── LaunchImage@3x.png
│ │ │ │ ├── README.md
│ │ │ │ └── Contents.json
│ │ │ ├── AppIcon.appiconset
│ │ │ │ ├── Icon-App-20x20@1x.png
│ │ │ │ ├── Icon-App-20x20@2x.png
│ │ │ │ ├── Icon-App-20x20@3x.png
│ │ │ │ ├── Icon-App-29x29@1x.png
│ │ │ │ ├── Icon-App-29x29@2x.png
│ │ │ │ ├── Icon-App-29x29@3x.png
│ │ │ │ ├── Icon-App-40x40@1x.png
│ │ │ │ ├── Icon-App-40x40@2x.png
│ │ │ │ ├── Icon-App-40x40@3x.png
│ │ │ │ ├── Icon-App-50x50@1x.png
│ │ │ │ ├── Icon-App-50x50@2x.png
│ │ │ │ ├── Icon-App-57x57@1x.png
│ │ │ │ ├── Icon-App-57x57@2x.png
│ │ │ │ ├── Icon-App-60x60@2x.png
│ │ │ │ ├── Icon-App-60x60@3x.png
│ │ │ │ ├── Icon-App-72x72@1x.png
│ │ │ │ ├── Icon-App-72x72@2x.png
│ │ │ │ ├── Icon-App-76x76@1x.png
│ │ │ │ ├── Icon-App-76x76@2x.png
│ │ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ │ └── Icon-App-83.5x83.5@2x.png
│ │ │ └── LaunchBackground.imageset
│ │ │ │ ├── background.png
│ │ │ │ ├── darkbackground.png
│ │ │ │ └── Contents.json
│ │ └── AppDelegate.swift
│ ├── Flutter
│ │ ├── Debug.xcconfig
│ │ ├── Release.xcconfig
│ │ └── AppFrameworkInfo.plist
│ ├── Runner.xcodeproj
│ │ └── project.xcworkspace
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata
│ │ │ ├── WorkspaceSettings.xcsettings
│ │ │ └── IDEWorkspaceChecks.plist
│ ├── Runner.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── WorkspaceSettings.xcsettings
│ │ │ └── IDEWorkspaceChecks.plist
│ └── .gitignore
├── assets
│ ├── splash.png
│ ├── docket-logo.png
│ └── google-calendar.png
├── android
│ ├── gradle.properties
│ ├── app
│ │ └── src
│ │ │ ├── main
│ │ │ ├── res
│ │ │ │ ├── drawable-hdpi
│ │ │ │ │ ├── splash.png
│ │ │ │ │ └── ic_launcher_foreground.png
│ │ │ │ ├── drawable-mdpi
│ │ │ │ │ ├── splash.png
│ │ │ │ │ └── ic_launcher_foreground.png
│ │ │ │ ├── drawable-xhdpi
│ │ │ │ │ ├── splash.png
│ │ │ │ │ └── ic_launcher_foreground.png
│ │ │ │ ├── drawable
│ │ │ │ │ ├── background.png
│ │ │ │ │ └── launch_background.xml
│ │ │ │ ├── drawable-v21
│ │ │ │ │ ├── background.png
│ │ │ │ │ └── launch_background.xml
│ │ │ │ ├── drawable-xxhdpi
│ │ │ │ │ ├── splash.png
│ │ │ │ │ └── ic_launcher_foreground.png
│ │ │ │ ├── drawable-xxxhdpi
│ │ │ │ │ ├── splash.png
│ │ │ │ │ └── ic_launcher_foreground.png
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── drawable-night
│ │ │ │ │ ├── background.png
│ │ │ │ │ └── launch_background.xml
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── values
│ │ │ │ │ └── colors.xml
│ │ │ │ ├── drawable-night-v21
│ │ │ │ │ ├── background.png
│ │ │ │ │ └── launch_background.xml
│ │ │ │ └── mipmap-anydpi-v26
│ │ │ │ │ └── ic_launcher.xml
│ │ │ ├── kotlin
│ │ │ │ └── com
│ │ │ │ │ └── docket
│ │ │ │ │ └── flutterapp
│ │ │ │ │ └── MainActivity.kt
│ │ │ └── java
│ │ │ │ └── io
│ │ │ │ └── flutter
│ │ │ │ └── app
│ │ │ │ └── FlutterMultiDexApplication.java
│ │ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ │ └── profile
│ │ │ └── AndroidManifest.xml
│ ├── gradle
│ │ └── wrapper
│ │ │ └── gradle-wrapper.properties
│ ├── .gitignore
│ ├── settings.gradle
│ └── build.gradle
├── test_resources
│ ├── login.json
│ ├── subtask_update.json
│ ├── profile.json
│ ├── calendar_source.json
│ ├── task_create_today.json
│ ├── task_details.json
│ ├── project_list.json
│ ├── tasks_today.json
│ ├── tasks_upcoming.json
│ ├── project_completed.json
│ └── project_details.json
├── lib
│ ├── screens
│ │ └── unknown.dart
│ ├── models
│ │ └── apitoken.dart
│ ├── components
│ │ ├── loadingindicator.dart
│ │ ├── taskgroup.dart
│ │ ├── projectbadge.dart
│ │ ├── taskaddbutton.dart
│ │ ├── iconsnackbar.dart
│ │ └── floatingcreatetaskbutton.dart
│ ├── viewmodels
│ │ ├── taskform.dart
│ │ └── login.dart
│ ├── db
│ │ ├── profile.dart
│ │ ├── trashbin.dart
│ │ └── projectarchive.dart
│ └── dialogs
│ │ └── confirmdelete.dart
├── .gitignore
├── test
│ └── theme_test.dart
└── .metadata
├── assets
├── sass
│ ├── components
│ │ ├── noProjects.scss
│ │ ├── sectionQuickForm.scss
│ │ ├── feedSubscriptions.scss
│ │ ├── projectBadge.scss
│ │ ├── confirm.scss
│ │ ├── taskGroup.scss
│ │ ├── dueOn.scss
│ │ ├── sectionContainer.scss
│ │ ├── profileMenu.scss
│ │ ├── markdownText.scss
│ │ ├── paginator.scss
│ │ ├── calendarItemList.scss
│ │ ├── flashMessage.scss
│ │ ├── modal.scss
│ │ ├── checkbox.scss
│ │ ├── icons.scss
│ │ └── projectItem.scss
│ ├── pages
│ │ ├── calendars
│ │ │ └── add.scss
│ │ ├── feeds
│ │ │ ├── viewitem.scss
│ │ │ └── discover.scss
│ │ ├── projects
│ │ │ └── view.scss
│ │ └── tasks
│ │ │ └── add.scss
│ └── utils.scss
└── js
│ ├── types.tsx
│ ├── extensions
│ ├── ajax.ts
│ ├── projectSorter.ts
│ ├── removeRow.ts
│ └── flashMessage.ts
│ ├── locale.ts
│ ├── webcomponents
│ ├── sideBar.ts
│ └── reloadAfter.ts
│ └── app.tsx
├── docker
├── run.sh
└── nginx.conf
├── .dockerignore
├── plugins
├── Feeds
│ ├── .gitignore
│ ├── templates
│ │ ├── FeedCategories
│ │ │ ├── reorder.php
│ │ │ ├── toggle_expanded.php
│ │ │ ├── delete_confirm.php
│ │ │ ├── edit.php
│ │ │ └── add.php
│ │ └── FeedSubscriptions
│ │ │ ├── delete_confirm.php
│ │ │ ├── add.php
│ │ │ └── edit.php
│ ├── src
│ │ ├── Service
│ │ │ └── FeedSyncException.php
│ │ ├── Policy
│ │ │ ├── FeedCategoriesTablePolicy.php
│ │ │ ├── FeedSubscriptionsTablePolicy.php
│ │ │ └── FeedItemsTablePolicy.php
│ │ ├── FeedsPlugin.php
│ │ ├── View
│ │ │ └── Cell
│ │ │ │ └── FeedCategoryMenuCell.php
│ │ └── Model
│ │ │ └── Entity
│ │ │ └── FeedItemUser.php
│ └── tests
│ │ └── Fixture
│ │ ├── FeedsFixture.php
│ │ ├── FeedItemsFixture.php
│ │ ├── FeedCategoriesFixture.php
│ │ ├── FeedItemUsersFixture.php
│ │ ├── SavedFeedItemsFixture.php
│ │ ├── FeedSubscriptionsFixture.php
│ │ └── FeedSubscriptionsFeedItemsFixture.php
├── Tasks
│ ├── .gitignore
│ ├── templates
│ │ ├── Projects
│ │ │ ├── reorder.php
│ │ │ ├── delete_confirm.php
│ │ │ ├── archived.php
│ │ │ ├── add.php
│ │ │ ├── edit.php
│ │ │ └── completed.php
│ │ ├── Tasks
│ │ │ ├── delete_ok.php
│ │ │ ├── reschedule.php
│ │ │ ├── delete_confirm.php
│ │ │ ├── deleted.php
│ │ │ ├── view.php
│ │ │ └── add.php
│ │ ├── ProjectSections
│ │ │ ├── view.php
│ │ │ ├── delete_confirm.php
│ │ │ ├── add.php
│ │ │ └── options.php
│ │ ├── element
│ │ │ ├── task_body.php
│ │ │ ├── task_checkbox.php
│ │ │ ├── tasks_empty.php
│ │ │ ├── project_item.php
│ │ │ └── task_due_on.php
│ │ └── cell
│ │ │ └── ProjectsMenu
│ │ │ └── display.php
│ ├── src
│ │ ├── TasksPlugin.php
│ │ ├── Policy
│ │ │ ├── ProjectsTablePolicy.php
│ │ │ └── TasksTablePolicy.php
│ │ └── View
│ │ │ └── Cell
│ │ │ └── ProjectsMenuCell.php
│ └── tests
│ │ └── Fixture
│ │ ├── TasksFixture.php
│ │ ├── ProjectsFixture.php
│ │ ├── SubtasksFixture.php
│ │ └── ProjectSectionsFixture.php
└── Calendar
│ ├── .gitignore
│ ├── templates
│ ├── GoogleOauth
│ │ └── complete.php
│ ├── element
│ │ ├── calendarprovider_tile.php
│ │ └── calendaritems.php
│ ├── CalendarSources
│ │ └── delete_confirm.php
│ └── CalendarProviders
│ │ └── index.php
│ ├── tests
│ └── Fixture
│ │ ├── CalendarItemsFixture.php
│ │ ├── CalendarSourcesFixture.php
│ │ ├── CalendarProvidersFixture.php
│ │ └── CalendarSubscriptionsFixture.php
│ └── src
│ ├── Policy
│ ├── CalendarProvidersTablePolicy.php
│ └── CalendarItemsTablePolicy.php
│ └── CalendarPlugin.php
├── templates
├── element
│ ├── icons
│ │ ├── README.md
│ │ ├── dot16.php
│ │ ├── kebab16.php
│ │ ├── chevron16.php
│ │ ├── check16.php
│ │ ├── chevron-right16.php
│ │ ├── clock16.php
│ │ ├── arrowleft16.php
│ │ ├── grabber24.php
│ │ ├── moon16.php
│ │ ├── checkcircle16.php
│ │ ├── plus16.php
│ │ ├── lock16.php
│ │ ├── alert16.php
│ │ ├── calendar16.php
│ │ ├── directory16.php
│ │ ├── note16.php
│ │ ├── rss16.php
│ │ ├── pencil16.php
│ │ ├── trash16.php
│ │ ├── clippy16.php
│ │ ├── sync16.php
│ │ ├── archive16.php
│ │ ├── link16.php
│ │ ├── workflow16.php
│ │ ├── directory-symlink16.php
│ │ ├── unlink16.php
│ │ ├── sun16.php
│ │ ├── LICENSE
│ │ └── trophy16.php
│ ├── flash
│ │ ├── error.php
│ │ ├── default.php
│ │ └── success.php
│ ├── frontend_assets.php
│ └── confirm_dialog.php
├── layout
│ ├── sheet.php
│ ├── card.php
│ ├── modal.php
│ ├── ajax.php
│ ├── error.php
│ ├── email
│ │ ├── text
│ │ │ └── default.php
│ │ └── html
│ │ │ └── default.php
│ └── default.php
├── email
│ ├── text
│ │ ├── reset_password.php
│ │ ├── verify_email.php
│ │ └── default.php
│ └── html
│ │ └── default.php
├── Pages
│ ├── home.php
│ └── manifest.php
├── Users
│ ├── reset_password.php
│ └── new_password.php
└── Error
│ ├── error400.php
│ └── error500.php
├── .phive
└── phars.xml
├── prettier.config.js
├── babel.config.js
├── .htaccess
├── .eslintrc.js
├── bin
├── cake.php
├── server.js
└── cake.bat
├── docker-compose.yaml
├── .editorconfig
├── psalm.xml
├── index.php
├── vite.config.ts
├── jest.config.js
├── phpcs.xml
├── LICENSE
├── tsconfig.json
└── .gitignore
/logs/.empty:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/config/Seeds/empty:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/webroot/js/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/Model/Behavior/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.yarnrc.yml:
--------------------------------------------------------------------------------
1 | nodeLinker: node-modules
2 |
--------------------------------------------------------------------------------
/tests/js/__mocks__/styleMock.js:
--------------------------------------------------------------------------------
1 | module.exports = {};
2 |
--------------------------------------------------------------------------------
/flutterapp/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/webroot/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/markstory/docket-app/HEAD/webroot/favicon.ico
--------------------------------------------------------------------------------
/webroot/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/markstory/docket-app/HEAD/webroot/favicon.png
--------------------------------------------------------------------------------
/webroot/img/cake-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/markstory/docket-app/HEAD/webroot/img/cake-logo.png
--------------------------------------------------------------------------------
/webroot/img/cake.icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/markstory/docket-app/HEAD/webroot/img/cake.icon.png
--------------------------------------------------------------------------------
/webroot/img/cake.power.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/markstory/docket-app/HEAD/webroot/img/cake.power.gif
--------------------------------------------------------------------------------
/flutterapp/assets/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/markstory/docket-app/HEAD/flutterapp/assets/splash.png
--------------------------------------------------------------------------------
/webroot/img/docket-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/markstory/docket-app/HEAD/webroot/img/docket-logo.png
--------------------------------------------------------------------------------
/assets/sass/components/noProjects.scss:
--------------------------------------------------------------------------------
1 | .no-projects {
2 | display: flex;
3 | flex-direction: column;
4 | }
5 |
--------------------------------------------------------------------------------
/flutterapp/assets/docket-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/markstory/docket-app/HEAD/flutterapp/assets/docket-logo.png
--------------------------------------------------------------------------------
/assets/sass/components/sectionQuickForm.scss:
--------------------------------------------------------------------------------
1 | .section-quickform {
2 | .title input {
3 | min-width: 200px;
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/flutterapp/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/flutterapp/assets/google-calendar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/markstory/docket-app/HEAD/flutterapp/assets/google-calendar.png
--------------------------------------------------------------------------------
/webroot/font/cakedingbats-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/markstory/docket-app/HEAD/webroot/font/cakedingbats-webfont.eot
--------------------------------------------------------------------------------
/webroot/font/cakedingbats-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/markstory/docket-app/HEAD/webroot/font/cakedingbats-webfont.ttf
--------------------------------------------------------------------------------
/webroot/font/cakedingbats-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/markstory/docket-app/HEAD/webroot/font/cakedingbats-webfont.woff
--------------------------------------------------------------------------------
/flutterapp/test_resources/login.json:
--------------------------------------------------------------------------------
1 | {
2 | "apiToken": {
3 | "token": "some-long-uuid",
4 | "last_used": null
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/webroot/font/cakedingbats-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/markstory/docket-app/HEAD/webroot/font/cakedingbats-webfont.woff2
--------------------------------------------------------------------------------
/assets/sass/pages/calendars/add.scss:
--------------------------------------------------------------------------------
1 | .calendar-name {
2 | display: flex;
3 | align-items: center;
4 | gap: calc($space / 2);
5 | }
6 |
--------------------------------------------------------------------------------
/docker/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | echo 'starting php-fpm in background'
3 | php-fpm &
4 |
5 | echo 'starting nginx'
6 | nginx -g 'daemon off;'
7 |
--------------------------------------------------------------------------------
/assets/sass/components/feedSubscriptions.scss:
--------------------------------------------------------------------------------
1 | .feed-subscriptions table {
2 | width: 100%;
3 |
4 | th {
5 | text-align: left;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/flutterapp/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/config/features.php:
--------------------------------------------------------------------------------
1 | [
6 | 'feed-reader' => false,
7 | ],
8 | ];
9 |
--------------------------------------------------------------------------------
/flutterapp/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/flutterapp/test_resources/subtask_update.json:
--------------------------------------------------------------------------------
1 | {
2 | "subtask": {
3 | "id": 1, "title": "fold big towels", "ranking": 1, "task_id": 1
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/webroot/.htaccess:
--------------------------------------------------------------------------------
1 |
You can close this browser view now.
5 |Your personal todo list
5 | 9 |Trash tasks will be deleted permanently after 14 days
16 | 17 | = $this->element('Tasks.task_item_restore', ['task' => $task]) ?> 18 | 19 | -------------------------------------------------------------------------------- /assets/sass/components/taskGroup.scss: -------------------------------------------------------------------------------- 1 | .task-group .add-task { 2 | margin-top: $space; 3 | } 4 | .task-group .dnd-item:last-child .task-row { 5 | border-bottom: 0; 6 | } 7 | 8 | .task-group + .heading-icon, 9 | .task-group + .heading-task-group { 10 | margin-top: calc($space * 5); 11 | } 12 | 13 | .empty-state-container { 14 | display: flex; 15 | flex-direction: column; 16 | align-items: center; 17 | 18 | .hero-icon { 19 | background: var(--color-bg-low); 20 | border-radius: 50%; 21 | padding: calc($space * 3); 22 | 23 | color: var(--color-success-fg); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /templates/element/icons/archive16.php: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /plugins/Tasks/templates/Tasks/view.php: -------------------------------------------------------------------------------- 1 | setLayout('sidebar'); 10 | $this->assign('title', 'Tasks - ' . h($task->title)); 11 | 12 | echo $this->element('Tasks.task_form', [ 13 | 'task' => $task, 14 | 'projects' => $projects, 15 | 'sections' => $sections, 16 | 'referer' => $referer, 17 | 'url' => ['_name' => 'tasks:edit', 'id' => $task->id], 18 | ]); 19 | -------------------------------------------------------------------------------- /src/Policy/UserPolicy.php: -------------------------------------------------------------------------------- 1 | id === $identity->id; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /webroot/img/docket-logo-translucent.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /flutterapp/lib/models/apitoken.dart: -------------------------------------------------------------------------------- 1 | class ApiToken { 2 | final int? id; 3 | final String token; 4 | final String? lastUsed; 5 | 6 | ApiToken({this.id, required this.token, this.lastUsed}); 7 | 8 | factory ApiToken.fromMap(MapYou don't have any archived projects.
20 |We will send you an email with instructions to reset it.
9 | = $this->Form->create( 10 | null, 11 | [ 12 | 'class' => 'form-narrow', 13 | 'url' => ['controller' => 'Users', 'action' => 'resetPassword'], 14 | ], 15 | ) ?> 16 | = $this->Form->control('email', ['required' => true, 'type' => 'email']) ?> 17 | 21 | = $this->Form->end() ?> 22 | -------------------------------------------------------------------------------- /flutterapp/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | tests.sqlite 13 | 14 | # IntelliJ related 15 | *.iml 16 | *.ipr 17 | *.iws 18 | .idea/ 19 | 20 | # Flutter/Dart/Pub related 21 | **/doc/api/ 22 | **/ios/Flutter/.last_build_id 23 | .dart_tool/ 24 | .flutter-plugins 25 | .flutter-plugins-dependencies 26 | .packages 27 | .pub-cache/ 28 | .pub/ 29 | /build/ 30 | /android/key.properties 31 | 32 | # Web related 33 | lib/generated_plugin_registrant.dart 34 | 35 | # Symbolication related 36 | app.*.symbols 37 | 38 | # Obfuscation related 39 | app.*.map.json 40 | 41 | # Android Studio will place build artifacts here 42 | /android/app/debug 43 | /android/app/profile 44 | /android/app/release 45 | -------------------------------------------------------------------------------- /config/schema/sessions.sql: -------------------------------------------------------------------------------- 1 | # Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) 2 | # 3 | # Licensed under The MIT License 4 | # For full copyright and license information, please see the LICENSE.txt 5 | # Redistributions of files must retain the above copyright notice. 6 | # MIT License (https://opensource.org/licenses/mit-license.php) 7 | 8 | CREATE TABLE `sessions` ( 9 | `id` char(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, 10 | `created` datetime DEFAULT CURRENT_TIMESTAMP, -- optional, requires MySQL 5.6.5+ 11 | `modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- optional, requires MySQL 5.6.5+ 12 | `data` blob DEFAULT NULL, -- for PostgreSQL use bytea instead of blob 13 | `expires` int(10) unsigned DEFAULT NULL, 14 | PRIMARY KEY (`id`) 15 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 16 | -------------------------------------------------------------------------------- /flutterapp/lib/db/profile.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_cache/json_cache.dart'; 2 | 3 | import 'package:docket/db/repository.dart'; 4 | import 'package:docket/models/userprofile.dart'; 5 | 6 | class ProfileRepo extends RepositoryCongratulations! Create a task for what is next.
12 |13 | = $this->Html->link( 14 | $this->element('icons/plus16') . 'Create a Task', 15 | ['_name' => 'tasks:add', '?' => $createParams], 16 | [ 17 | 'escape' => false, 18 | 'class' => 'button-primary', 19 | 'hx-get' => $this->Url->build(['_name' => 'tasks:add', '?' => $createParams]), 20 | 'hx-target' => 'main.main', 21 | 'hx-swap' => 'beforeend', 22 | ] 23 | ) ?> 24 |
25 |19 | Events from linked calendars will be displayed in "today" and "upcoming" views. 20 |
21 |20 | SQL Query: 21 | = h($error->queryString) ?> 22 |
23 | 24 | params)) : ?> 25 | SQL Query Params: 26 | params) ?> 27 | 28 | = $this->element('auto_table_warning') ?> 29 | end(); 32 | endif; 33 | ?> 34 |36 | = __d('cake', 'Error') ?>: 37 | = __d('cake', 'The requested address {0} was not found on this server.', "'{$url}'") ?> 38 |
39 | -------------------------------------------------------------------------------- /flutterapp/test_resources/tasks_today.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": [ 3 | { 4 | "id": 1, 5 | "project": {"id": 1, "slug": "home", "name": "home", "color": 1}, 6 | "title": "clean dishes", 7 | "body": "", 8 | "evening": false, 9 | "completed": false, 10 | "due_on": "__TODAY__", 11 | "child_order": 0, 12 | "day_order": 0 13 | }, 14 | { 15 | "id": 2, 16 | "project": {"id": 1, "slug": "home", "name": "home", "color": 1}, 17 | "title": "cut grass", 18 | "body": "", 19 | "evening": false, 20 | "completed": false, 21 | "due_on": "__TODAY__", 22 | "child_order": 1, 23 | "day_order": 1 24 | } 25 | ], 26 | "calendarItems": [ 27 | { 28 | "id": 1, 29 | "calendar_source_id": 1, 30 | "provider_id": "google", 31 | "color": 1, 32 | "title": "Get haircut", 33 | "start_time": null, 34 | "end_time": null, 35 | "start_date": "__TODAY__", 36 | "end_date": "__TODAY__", 37 | "all_day": true, 38 | "html_link": "" 39 | } 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /assets/sass/components/flashMessage.scss: -------------------------------------------------------------------------------- 1 | @keyframes flash-message-append { 2 | from { 3 | top: -60px; 4 | } 5 | to { 6 | top: 16px; 7 | } 8 | } 9 | .flash-messages { 10 | display: flex; 11 | flex-direction: column; 12 | gap: $space; 13 | 14 | position: fixed; 15 | left: 50%; 16 | top: 16px; 17 | width: max-content; 18 | transform: translateX(-50%); 19 | z-index: $z-flash; 20 | } 21 | 22 | .flash-message { 23 | animation: 0.5s ease-out 0s 1 flash-message-append; 24 | 25 | padding: $space * 2; 26 | background: var(--color-bg); 27 | box-shadow: var(--shadow-med); 28 | border-radius: $border-radius; 29 | 30 | svg { 31 | margin-right: $space; 32 | vertical-align: -0.225em; 33 | } 34 | 35 | transition: top 0.3s, opacity 0.3s; 36 | 37 | &[data-state="visible"] { 38 | top: 16px; 39 | } 40 | &[data-state="hidden"] { 41 | top: -60px; 42 | opacity: 0; 43 | display: none; 44 | } 45 | } 46 | 47 | .flash-success svg { 48 | color: var(--color-success-fg); 49 | } 50 | .flash-error svg { 51 | color: var(--color-error-fg); 52 | } 53 | 54 | -------------------------------------------------------------------------------- /flutterapp/test_resources/tasks_upcoming.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": [ 3 | { 4 | "id": 1, 5 | "project": {"id": 1, "slug": "home", "name": "home", "color": 1}, 6 | "title": "clean dishes", 7 | "body": "", 8 | "evening": false, 9 | "completed": false, 10 | "due_on": "__TODAY__", 11 | "child_order": 0, 12 | "day_order": 0 13 | }, 14 | { 15 | "id": 2, 16 | "project": {"id": 1, "slug": "home", "name": "home", "color": 1}, 17 | "title": "cut grass", 18 | "body": "", 19 | "evening": false, 20 | "completed": false, 21 | "due_on": "__TOMORROW__", 22 | "child_order": 1, 23 | "day_order": 1 24 | } 25 | ], 26 | "calendarItems": [ 27 | { 28 | "id": 1, 29 | "calendar_source_id": 1, 30 | "provider_id": "google", 31 | "color": 1, 32 | "title": "Get haircut", 33 | "start_time": null, 34 | "end_time": null, 35 | "start_date": "__TODAY__", 36 | "end_date": "__TODAY__", 37 | "all_day": true, 38 | "html_link": "" 39 | } 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /templates/element/confirm_dialog.php: -------------------------------------------------------------------------------- 1 | setLayout('modal'); 13 | 14 | $this->set('closable', false); 15 | $this->set('dialogOptions', [ 16 | 'class' => 'confirm-dialog', 17 | 'data-testid' => 'confirm-dialog', 18 | ]); 19 | ?> 20 | = $this->Form->create(null, ['url' => $target]) ?> 21 |= $description ?>
23 | 36 | = $this->Form->end() ?> 37 | -------------------------------------------------------------------------------- /flutterapp/test_resources/project_completed.json: -------------------------------------------------------------------------------- 1 | { 2 | "project": { 3 | "id": 1, 4 | "name": "Home", 5 | "slug": "home", 6 | "color": 1, 7 | "ranking": 2, 8 | "incomplete_task_count": 3, 9 | "sections": [ 10 | { 11 | "id": 1, 12 | "name": "Chores", 13 | "ranking": 1 14 | }, 15 | { 16 | "id": 2, 17 | "name": "Bills", 18 | "ranking": 0 19 | } 20 | ] 21 | }, 22 | "tasks": [ 23 | { 24 | "id": 1, 25 | "project": {"id": 1, "slug": "home", "name": "home", "color": 1}, 26 | "title": "clean dishes", 27 | "body": "", 28 | "evening": false, 29 | "completed": true, 30 | "due_on": null, 31 | "child_order": 0, 32 | "day_order": 0 33 | }, 34 | { 35 | "id": 2, 36 | "project": {"id": 1, "slug": "home", "name": "home", "color": 1}, 37 | "title": "cut grass", 38 | "body": "", 39 | "evening": false, 40 | "completed": true, 41 | "due_on": null, 42 | "child_order": 1, 43 | "day_order": 1 44 | } 45 | ] 46 | } 47 | -------------------------------------------------------------------------------- /flutterapp/test_resources/project_details.json: -------------------------------------------------------------------------------- 1 | { 2 | "project": { 3 | "id": 1, 4 | "name": "Home", 5 | "slug": "home", 6 | "color": 1, 7 | "ranking": 2, 8 | "incomplete_task_count": 3, 9 | "sections": [ 10 | { 11 | "id": 1, 12 | "name": "Chores", 13 | "ranking": 1 14 | }, 15 | { 16 | "id": 2, 17 | "name": "Bills", 18 | "ranking": 2 19 | } 20 | ] 21 | }, 22 | "tasks": [ 23 | { 24 | "id": 1, 25 | "project": {"id": 1, "slug": "home", "name": "home", "color": 1}, 26 | "title": "clean dishes", 27 | "body": "", 28 | "evening": false, 29 | "completed": false, 30 | "due_on": null, 31 | "child_order": 0, 32 | "day_order": 0 33 | }, 34 | { 35 | "id": 2, 36 | "project": {"id": 1, "slug": "home", "name": "home", "color": 1}, 37 | "title": "cut grass", 38 | "body": "", 39 | "evening": false, 40 | "completed": false, 41 | "due_on": null, 42 | "child_order": 1, 43 | "day_order": 1 44 | } 45 | ] 46 | } 47 | -------------------------------------------------------------------------------- /plugins/Tasks/templates/Projects/completed.php: -------------------------------------------------------------------------------- 1 | setLayout('sidebar'); 8 | $this->assign('title', $project->name . ' Completed Tasks'); 9 | 10 | ?> 11 |Update your password. Your password must be at least 10 characters long.
13 | = $this->Form->create( 14 | $user, 15 | [ 16 | 'type' => 'post', 17 | 'url' => ['controller' => 'Users', 'action' => 'newPassword', $token], 18 | ], 19 | ) ?> 20 | = $this->Form->control('password', [ 21 | 'type' => 'password', 22 | 'value' => '', 23 | 'required' => true, 24 | ]) ?> 25 | = $this->Form->control('confirm_password', [ 26 | 'type' => 'password', 27 | 'value' => '', 28 | 'required' => true, 29 | ]) ?> 30 | 38 | 39 | -------------------------------------------------------------------------------- /assets/sass/components/modal.scss: -------------------------------------------------------------------------------- 1 | .modal-title { 2 | display: flex; 3 | justify-content: space-between; 4 | align-items: center; 5 | 6 | margin-bottom: calc($space * 3); 7 | 8 | h1, h2, h3, h4 { 9 | margin: 0; 10 | } 11 | } 12 | 13 | .modal-close { 14 | @extend .button-bare; 15 | 16 | display: flex; 17 | justify-content: center; 18 | position: relative; 19 | top: -16px; 20 | right: -16px; 21 | 22 | border: none; 23 | border-radius: 50%; 24 | font-size: $font-size-large; 25 | line-height: $font-size-large; 26 | height: 30px; 27 | width: 30px; 28 | padding: 5px; 29 | margin: 0; 30 | box-shadow: none; 31 | } 32 | 33 | .modal-sheet { 34 | width: 75%; 35 | max-width: 850px; 36 | min-height: 80%; 37 | } 38 | .modal-sheet.feed-subscriptions-edit { 39 | max-width: 600px; 40 | min-height: auto; 41 | } 42 | @media (max-width: $breakpoint-phone) { 43 | .modal-sheet { 44 | height: 95%; 45 | width: 95%; 46 | } 47 | } 48 | 49 | .modal-contents { 50 | height: 100%; 51 | overflow: auto; 52 | } 53 | 54 | modal-window .flash-message { 55 | margin-bottom: calc($space * 3); 56 | } 57 | -------------------------------------------------------------------------------- /src/Identifier/ApiTokenIdentifier.php: -------------------------------------------------------------------------------- 1 | fetchTable('ApiTokens'); 21 | 22 | /** @var \App\Model\Entity\ApiToken|null $tokenUser */ 23 | $tokenUser = $apiTokens->find() 24 | ->where(['ApiTokens.token' => $credentials['token']]) 25 | ->contain('Users') 26 | ->first(); 27 | 28 | if (!$tokenUser) { 29 | return null; 30 | } 31 | 32 | // Update the last used timestamp. 33 | $tokenUser->last_used = new DateTime(); 34 | $apiTokens->save($tokenUser); 35 | 36 | return $tokenUser->user; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /assets/sass/components/checkbox.scss: -------------------------------------------------------------------------------- 1 | $checkbox-size: 16px; 2 | 3 | .checkbox { 4 | position: relative; 5 | min-width: $checkbox-size; 6 | width: $checkbox-size; 7 | margin: 0; 8 | 9 | .box { 10 | display: block; 11 | cursor: pointer; 12 | width: $checkbox-size; 13 | height: $checkbox-size; 14 | border: 1px solid var(--color-border-med); 15 | border-radius: 4px; 16 | } 17 | input:checked ~ .box { 18 | border-color: var(--color-success-fg); 19 | } 20 | 21 | input:active ~ .box, 22 | input:focus ~ .box { 23 | border-color: var(--color-input-focus-border); 24 | box-shadow: var(--color-input-focus-shadow) 0 0 0 3px; 25 | } 26 | 27 | // Hide the input without removing tabindex. 28 | input { 29 | opacity: 0; 30 | position: absolute; 31 | pointer-events: none; 32 | } 33 | svg { 34 | color: var(--color-success-fg); 35 | width: 14px; 36 | height: 14px; 37 | } 38 | 39 | .check { 40 | visibility: hidden; 41 | position: absolute; 42 | top: 1px; 43 | left: 1px; 44 | } 45 | input:checked ~ .check { 46 | visibility: visible; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /assets/sass/components/icons.scss: -------------------------------------------------------------------------------- 1 | .icon-error { 2 | color: var(--color-error-fg); 3 | } 4 | 5 | // Colored icon utilities 6 | .icon-today svg, 7 | .today svg { 8 | color: var(--color-due-today); 9 | } 10 | .icon-tomorrow svg, 11 | .tomorrow svg { 12 | color: var(--color-due-tomorrow); 13 | } 14 | .icon-evening svg, 15 | .evening svg { 16 | color: var(--color-due-evening); 17 | } 18 | .icon-not-due svg, 19 | .not-due svg { 20 | color: var(--color-due-none); 21 | } 22 | .none { 23 | color: var(--color-due-none); 24 | } 25 | .icon-overdue svg, 26 | .overdue { 27 | color: var(--color-due-overdue); 28 | } 29 | .icon-week svg, 30 | .week { 31 | color: var(--color-due-week); 32 | } 33 | .icon-fortnight svg, 34 | .fortnight { 35 | color: var(--color-due-fortnight); 36 | } 37 | .icon-delete svg { 38 | color: var(--color-action-delete); 39 | } 40 | .icon-archive svg { 41 | color: var(--color-low-emphasis); 42 | } 43 | .icon-edit svg { 44 | color: var(--color-action-edit); 45 | } 46 | .icon-lock svg { 47 | color: var(--color-action-lock); 48 | } 49 | .icon-complete svg { 50 | color: var(--color-action-complete); 51 | } 52 | 53 | -------------------------------------------------------------------------------- /templates/layout/default.php: -------------------------------------------------------------------------------- 1 | theme}"; 7 | endif; 8 | ?> 9 | 10 | 11 | 12 | = $this->Html->charset() ?> 13 | 14 | 15 |17 | Sections help organize tasks in a project into logical chunks. 18 | When a section is deleted, all the tasks within that section are also deleted. 19 | Sections in a project can be sorted as you see fit. 20 |
21 | Form->create($section, [ 23 | 'class' => 'form-modal', 24 | ]); 25 | echo $this->Form->hidden('referer', ['value' => $referer]); 26 | echo $this->Form->control('name'); 27 | ?> 28 | 34 | = $this->Form->end() ?> 35 | -------------------------------------------------------------------------------- /plugins/Feeds/templates/FeedSubscriptions/edit.php: -------------------------------------------------------------------------------- 1 | request->is('htmx'); 8 | 9 | $this->setLayout('sidebar'); 10 | if ($isHtmx) { 11 | $this->setLayout('sheet'); 12 | $this->set('sheet.class', 'feed-subscriptions-edit'); 13 | } 14 | 15 | $this->assign('title', 'Edit Feed'); 16 | ?> 17 |20 | SQL Query: 21 | = h($error->queryString) ?> 22 |
23 | 24 | params)) : ?> 25 | SQL Query Params: 26 | params) ?> 27 | 28 | 29 | Error in: 30 | = sprintf('%s, line %s', str_replace(ROOT, 'ROOT', $error->getFile()), $error->getLine()) ?> 31 | 32 | element('auto_table_warning'); 34 | 35 | $this->end(); 36 | endif; 37 | ?> 38 |40 | = __d('cake', 'Error') ?>: 41 | = h($message) ?> 42 |
43 | -------------------------------------------------------------------------------- /flutterapp/lib/components/iconsnackbar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:docket/theme.dart'; 3 | 4 | SnackBar successSnackBar({BuildContext? context, ThemeData? theme, required String text}) { 5 | assert(context != null || theme != null, "one of theme or context is required"); 6 | 7 | theme = theme ?? Theme.of(context!); 8 | var colors = theme.extension