Showing preview only (4,320K chars total). Download the full file or copy to clipboard to get everything.
Repository: solidtime-io/solidtime
Branch: main
Commit: 192c8c3b887a
Files: 1208
Total size: 3.9 MB
Directory structure:
gitextract_ryuvl2mb/
├── .editorconfig
├── .gitattributes
├── .github/
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── 1_bug_report.yml
│ │ └── config.yml
│ ├── PULL_REQUEST_TEMPLATE.md
│ ├── dependabot.yml
│ └── workflows/
│ ├── build-onpremise.yml
│ ├── build-private.yml
│ ├── build-public.yml
│ ├── generate-api-docs.yml
│ ├── npm-build.yml
│ ├── npm-format-check.yml
│ ├── npm-lint.yml
│ ├── npm-publish-api.yml
│ ├── npm-publish-ui.yml
│ ├── npm-typecheck.yml
│ ├── phpstan.yml
│ ├── phpunit.yml
│ ├── pint.yml
│ └── playwright.yml
├── .gitignore
├── .prettierignore
├── .prettierrc.json
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE.md
├── README.md
├── SECURITY.md
├── app/
│ ├── Actions/
│ │ ├── Fortify/
│ │ │ ├── CreateNewUser.php
│ │ │ ├── PasswordValidationRules.php
│ │ │ ├── ResetUserPassword.php
│ │ │ ├── UpdateUserPassword.php
│ │ │ └── UpdateUserProfileInformation.php
│ │ └── Jetstream/
│ │ ├── AddOrganizationMember.php
│ │ ├── CreateOrganization.php
│ │ ├── DeleteOrganization.php
│ │ ├── DeleteUser.php
│ │ ├── InviteOrganizationMember.php
│ │ ├── RemoveOrganizationMember.php
│ │ ├── UpdateMemberRole.php
│ │ ├── UpdateOrganization.php
│ │ └── ValidateOrganizationDeletion.php
│ ├── Console/
│ │ ├── Commands/
│ │ │ ├── Admin/
│ │ │ │ ├── OrganizationDeleteCommand.php
│ │ │ │ ├── UserCreateCommand.php
│ │ │ │ └── UserVerifyCommand.php
│ │ │ ├── Auth/
│ │ │ │ └── AuthSendReminderForExpiringApiTokensCommand.php
│ │ │ ├── Correction/
│ │ │ │ └── CorrectionPlaceholderMembersCommand.php
│ │ │ ├── Report/
│ │ │ │ └── ReportSetExpiredToPrivateCommand.php
│ │ │ ├── SelfHost/
│ │ │ │ ├── SelfHostCheckForUpdateCommand.php
│ │ │ │ ├── SelfHostDatabaseConsistency.php
│ │ │ │ ├── SelfHostGenerateKeysCommand.php
│ │ │ │ └── SelfHostTelemetryCommand.php
│ │ │ ├── Test/
│ │ │ │ ├── TestEmailCommand.php
│ │ │ │ ├── TestJobCommand.php
│ │ │ │ └── TestOutputCommand.php
│ │ │ └── TimeEntry/
│ │ │ └── TimeEntrySendStillRunningMailsCommand.php
│ │ └── Kernel.php
│ ├── Enums/
│ │ ├── CurrencyFormat.php
│ │ ├── DateFormat.php
│ │ ├── ExportFormat.php
│ │ ├── IntervalFormat.php
│ │ ├── NumberFormat.php
│ │ ├── Role.php
│ │ ├── TimeEntryAggregationType.php
│ │ ├── TimeEntryAggregationTypeInterval.php
│ │ ├── TimeEntryRoundingType.php
│ │ ├── TimeFormat.php
│ │ └── Weekday.php
│ ├── Events/
│ │ ├── AfterCreateOrganization.php
│ │ ├── BeforeOrganizationDeletion.php
│ │ ├── DatabaseSeederAfterSeed.php
│ │ ├── DatabaseSeederBeforeDelete.php
│ │ ├── MemberMadeToPlaceholder.php
│ │ ├── MemberRemoved.php
│ │ └── NewsletterRegistered.php
│ ├── Exceptions/
│ │ ├── Api/
│ │ │ ├── ApiException.php
│ │ │ ├── CanNotDeleteUserWhoIsOwnerOfOrganizationWithMultipleMembers.php
│ │ │ ├── CanNotRemoveOwnerFromOrganization.php
│ │ │ ├── ChangingRoleOfPlaceholderIsNotAllowed.php
│ │ │ ├── ChangingRoleToPlaceholderIsNotAllowed.php
│ │ │ ├── EntityStillInUseApiException.php
│ │ │ ├── FeatureIsNotAvailableInFreePlanApiException.php
│ │ │ ├── InactiveUserCanNotBeUsedApiException.php
│ │ │ ├── InvitationForTheEmailAlreadyExistsApiException.php
│ │ │ ├── OnlyOwnerCanChangeOwnership.php
│ │ │ ├── OnlyPlaceholdersCanBeMergedIntoAnotherMember.php
│ │ │ ├── OrganizationHasNoSubscriptionButMultipleMembersException.php
│ │ │ ├── OrganizationNeedsAtLeastOneOwner.php
│ │ │ ├── OverlappingTimeEntryApiException.php
│ │ │ ├── PdfRendererIsNotConfiguredException.php
│ │ │ ├── PersonalAccessClientIsNotConfiguredException.php
│ │ │ ├── ThisPlaceholderCanNotBeInvitedUseTheMergeToolInsteadException.php
│ │ │ ├── TimeEntryCanNotBeRestartedApiException.php
│ │ │ ├── TimeEntryStillRunningApiException.php
│ │ │ ├── UserIsAlreadyMemberOfOrganizationApiException.php
│ │ │ ├── UserIsAlreadyMemberOfProjectApiException.php
│ │ │ └── UserNotPlaceholderApiException.php
│ │ ├── Handler.php
│ │ └── MovedToApiException.php
│ ├── Extensions/
│ │ ├── Auditing/
│ │ │ └── Resolvers/
│ │ │ └── CustomIpAddressResolver.php
│ │ ├── Fortify/
│ │ │ ├── CustomLoginResponse.php
│ │ │ └── CustomTwoFactorLoginResponse.php
│ │ └── Scramble/
│ │ ├── ApiExceptionTypeToSchema.php
│ │ └── PaginatedResourceCollectionTypeToSchema.php
│ ├── Filament/
│ │ ├── Resources/
│ │ │ ├── AuditResource/
│ │ │ │ └── Pages/
│ │ │ │ ├── CreateAudit.php
│ │ │ │ ├── ListAudits.php
│ │ │ │ └── ViewAudit.php
│ │ │ ├── AuditResource.php
│ │ │ ├── ClientResource/
│ │ │ │ └── Pages/
│ │ │ │ ├── CreateClient.php
│ │ │ │ ├── EditClient.php
│ │ │ │ └── ListClients.php
│ │ │ ├── ClientResource.php
│ │ │ ├── FailedJobResource/
│ │ │ │ └── Pages/
│ │ │ │ ├── ListFailedJobs.php
│ │ │ │ └── ViewFailedJobs.php
│ │ │ ├── FailedJobResource.php
│ │ │ ├── OrganizationInvitationResource/
│ │ │ │ └── Pages/
│ │ │ │ ├── EditOrganizationInvitation.php
│ │ │ │ ├── ListOrganizationInvitations.php
│ │ │ │ └── ViewOrganizationInvitation.php
│ │ │ ├── OrganizationInvitationResource.php
│ │ │ ├── OrganizationResource/
│ │ │ │ ├── Actions/
│ │ │ │ │ └── DeleteOrganization.php
│ │ │ │ ├── Pages/
│ │ │ │ │ ├── CreateOrganization.php
│ │ │ │ │ ├── EditOrganization.php
│ │ │ │ │ ├── ListOrganizations.php
│ │ │ │ │ └── ViewOrganization.php
│ │ │ │ └── RelationManagers/
│ │ │ │ ├── InvitationsRelationManager.php
│ │ │ │ └── UsersRelationManager.php
│ │ │ ├── OrganizationResource.php
│ │ │ ├── ProjectMemberResource/
│ │ │ │ └── Pages/
│ │ │ │ ├── CreateProjectMember.php
│ │ │ │ ├── EditProjectMember.php
│ │ │ │ ├── ListProjectMembers.php
│ │ │ │ └── ViewProjectMembers.php
│ │ │ ├── ProjectMemberResource.php
│ │ │ ├── ProjectResource/
│ │ │ │ ├── Pages/
│ │ │ │ │ ├── CreateProject.php
│ │ │ │ │ ├── EditProject.php
│ │ │ │ │ └── ListProjects.php
│ │ │ │ └── RelationManagers/
│ │ │ │ └── ProjectMembersRelationManager.php
│ │ │ ├── ProjectResource.php
│ │ │ ├── ReportResource/
│ │ │ │ └── Pages/
│ │ │ │ ├── EditReport.php
│ │ │ │ ├── ListReports.php
│ │ │ │ └── ViewReport.php
│ │ │ ├── ReportResource.php
│ │ │ ├── TagResource/
│ │ │ │ └── Pages/
│ │ │ │ ├── CreateTag.php
│ │ │ │ ├── EditTag.php
│ │ │ │ └── ListTags.php
│ │ │ ├── TagResource.php
│ │ │ ├── TaskResource/
│ │ │ │ └── Pages/
│ │ │ │ ├── CreateTask.php
│ │ │ │ ├── EditTask.php
│ │ │ │ └── ListTasks.php
│ │ │ ├── TaskResource.php
│ │ │ ├── TimeEntryResource/
│ │ │ │ └── Pages/
│ │ │ │ ├── CreateTimeEntry.php
│ │ │ │ ├── EditTimeEntry.php
│ │ │ │ └── ListTimeEntries.php
│ │ │ ├── TimeEntryResource.php
│ │ │ ├── TokenResource/
│ │ │ │ └── Pages/
│ │ │ │ ├── ListTokens.php
│ │ │ │ └── ViewToken.php
│ │ │ ├── TokenResource.php
│ │ │ ├── UserResource/
│ │ │ │ ├── Actions/
│ │ │ │ │ └── DeleteUser.php
│ │ │ │ ├── Pages/
│ │ │ │ │ ├── CreateUser.php
│ │ │ │ │ ├── EditUser.php
│ │ │ │ │ ├── ListUsers.php
│ │ │ │ │ └── ViewUser.php
│ │ │ │ └── RelationManagers/
│ │ │ │ ├── OrganizationsRelationManager.php
│ │ │ │ └── OwnedOrganizationsRelationManager.php
│ │ │ └── UserResource.php
│ │ └── Widgets/
│ │ ├── ActiveUserOverview.php
│ │ ├── ServerOverview.php
│ │ ├── TimeEntriesCreated.php
│ │ ├── TimeEntriesImported.php
│ │ └── UserRegistrations.php
│ ├── Http/
│ │ ├── Controllers/
│ │ │ ├── Api/
│ │ │ │ └── V1/
│ │ │ │ ├── ApiTokenController.php
│ │ │ │ ├── ChartController.php
│ │ │ │ ├── ClientController.php
│ │ │ │ ├── Controller.php
│ │ │ │ ├── CurrencyController.php
│ │ │ │ ├── ExportController.php
│ │ │ │ ├── ImportController.php
│ │ │ │ ├── InvitationController.php
│ │ │ │ ├── MemberController.php
│ │ │ │ ├── OrganizationController.php
│ │ │ │ ├── ProjectController.php
│ │ │ │ ├── ProjectMemberController.php
│ │ │ │ ├── Public/
│ │ │ │ │ └── ReportController.php
│ │ │ │ ├── ReportController.php
│ │ │ │ ├── TagController.php
│ │ │ │ ├── TaskController.php
│ │ │ │ ├── TimeEntryController.php
│ │ │ │ ├── UserController.php
│ │ │ │ ├── UserMembershipController.php
│ │ │ │ └── UserTimeEntryController.php
│ │ │ ├── Controller.php
│ │ │ └── Web/
│ │ │ ├── Controller.php
│ │ │ ├── DashboardController.php
│ │ │ ├── HealthCheckController.php
│ │ │ └── HomeController.php
│ │ ├── Kernel.php
│ │ ├── Middleware/
│ │ │ ├── Authenticate.php
│ │ │ ├── CheckOrganizationBlocked.php
│ │ │ ├── EncryptCookies.php
│ │ │ ├── EnsureEmailIsVerified.php
│ │ │ ├── ForceHttps.php
│ │ │ ├── ForceJsonResponse.php
│ │ │ ├── HandleInertiaRequests.php
│ │ │ ├── PreventRequestsDuringMaintenance.php
│ │ │ ├── RedirectIfAuthenticated.php
│ │ │ ├── ShareInertiaData.php
│ │ │ ├── TrimStrings.php
│ │ │ ├── TrustProxies.php
│ │ │ ├── ValidateSignature.php
│ │ │ └── VerifyCsrfToken.php
│ │ ├── Requests/
│ │ │ └── V1/
│ │ │ ├── ApiToken/
│ │ │ │ └── ApiTokenStoreRequest.php
│ │ │ ├── BaseFormRequest.php
│ │ │ ├── Client/
│ │ │ │ ├── ClientIndexRequest.php
│ │ │ │ ├── ClientStoreRequest.php
│ │ │ │ └── ClientUpdateRequest.php
│ │ │ ├── Import/
│ │ │ │ └── ImportRequest.php
│ │ │ ├── Invitation/
│ │ │ │ ├── InvitationIndexRequest.php
│ │ │ │ └── InvitationStoreRequest.php
│ │ │ ├── Member/
│ │ │ │ ├── MemberDestroyRequest.php
│ │ │ │ ├── MemberIndexRequest.php
│ │ │ │ ├── MemberMergeIntoRequest.php
│ │ │ │ └── MemberUpdateRequest.php
│ │ │ ├── Organization/
│ │ │ │ └── OrganizationUpdateRequest.php
│ │ │ ├── Project/
│ │ │ │ ├── ProjectIndexRequest.php
│ │ │ │ ├── ProjectStoreRequest.php
│ │ │ │ └── ProjectUpdateRequest.php
│ │ │ ├── ProjectMember/
│ │ │ │ ├── ProjectMemberIndexRequest.php
│ │ │ │ ├── ProjectMemberStoreRequest.php
│ │ │ │ └── ProjectMemberUpdateRequest.php
│ │ │ ├── Report/
│ │ │ │ ├── ReportIndexRequest.php
│ │ │ │ ├── ReportStoreRequest.php
│ │ │ │ └── ReportUpdateRequest.php
│ │ │ ├── Tag/
│ │ │ │ ├── TagIndexRequest.php
│ │ │ │ ├── TagStoreRequest.php
│ │ │ │ └── TagUpdateRequest.php
│ │ │ ├── Task/
│ │ │ │ ├── TaskIndexRequest.php
│ │ │ │ ├── TaskStoreRequest.php
│ │ │ │ └── TaskUpdateRequest.php
│ │ │ └── TimeEntry/
│ │ │ ├── TimeEntryAggregateExportRequest.php
│ │ │ ├── TimeEntryAggregateRequest.php
│ │ │ ├── TimeEntryDestroyMultipleRequest.php
│ │ │ ├── TimeEntryIndexExportRequest.php
│ │ │ ├── TimeEntryIndexRequest.php
│ │ │ ├── TimeEntryStoreRequest.php
│ │ │ ├── TimeEntryUpdateMultipleRequest.php
│ │ │ └── TimeEntryUpdateRequest.php
│ │ └── Resources/
│ │ ├── PaginatedResourceCollection.php
│ │ └── V1/
│ │ ├── ApiToken/
│ │ │ ├── ApiTokenCollection.php
│ │ │ ├── ApiTokenResource.php
│ │ │ └── ApiTokenWithAccessTokenResource.php
│ │ ├── BaseResource.php
│ │ ├── Client/
│ │ │ ├── ClientCollection.php
│ │ │ └── ClientResource.php
│ │ ├── Invitation/
│ │ │ ├── InvitationCollection.php
│ │ │ └── InvitationResource.php
│ │ ├── Member/
│ │ │ ├── MemberCollection.php
│ │ │ ├── MemberResource.php
│ │ │ ├── PersonalMembershipCollection.php
│ │ │ └── PersonalMembershipResource.php
│ │ ├── Organization/
│ │ │ └── OrganizationResource.php
│ │ ├── Project/
│ │ │ ├── ProjectCollection.php
│ │ │ └── ProjectResource.php
│ │ ├── ProjectMember/
│ │ │ ├── ProjectMemberCollection.php
│ │ │ └── ProjectMemberResource.php
│ │ ├── Report/
│ │ │ ├── DetailedReportResource.php
│ │ │ ├── DetailedWithDataReportResource.php
│ │ │ ├── ReportCollection.php
│ │ │ └── ReportResource.php
│ │ ├── Tag/
│ │ │ ├── TagCollection.php
│ │ │ └── TagResource.php
│ │ ├── Task/
│ │ │ ├── TaskCollection.php
│ │ │ └── TaskResource.php
│ │ ├── TimeEntry/
│ │ │ ├── TimeEntryCollection.php
│ │ │ └── TimeEntryResource.php
│ │ └── User/
│ │ └── UserResource.php
│ ├── Jobs/
│ │ ├── RecalculateSpentTimeForProject.php
│ │ ├── RecalculateSpentTimeForTask.php
│ │ └── Test/
│ │ └── TestJob.php
│ ├── Listeners/
│ │ └── RemovePlaceholder.php
│ ├── Mail/
│ │ ├── AuthApiTokenExpirationReminderMail.php
│ │ ├── AuthApiTokenExpiredMail.php
│ │ ├── OrganizationInvitationMail.php
│ │ └── TimeEntryStillRunningMail.php
│ ├── Models/
│ │ ├── Audit.php
│ │ ├── Client.php
│ │ ├── Concerns/
│ │ │ ├── CustomAuditable.php
│ │ │ └── HasUuids.php
│ │ ├── FailedJob.php
│ │ ├── Member.php
│ │ ├── Organization.php
│ │ ├── OrganizationInvitation.php
│ │ ├── Passport/
│ │ │ ├── AuthCode.php
│ │ │ ├── Client.php
│ │ │ ├── RefreshToken.php
│ │ │ └── Token.php
│ │ ├── Project.php
│ │ ├── ProjectMember.php
│ │ ├── Report.php
│ │ ├── Tag.php
│ │ ├── Task.php
│ │ ├── TimeEntry.php
│ │ └── User.php
│ ├── Policies/
│ │ └── OrganizationPolicy.php
│ ├── Providers/
│ │ ├── AppServiceProvider.php
│ │ ├── AuthServiceProvider.php
│ │ ├── EventServiceProvider.php
│ │ ├── Filament/
│ │ │ └── AdminPanelProvider.php
│ │ ├── FortifyServiceProvider.php
│ │ ├── JetstreamServiceProvider.php
│ │ ├── RouteServiceProvider.php
│ │ └── TelescopeServiceProvider.php
│ ├── Rules/
│ │ ├── ColorRule.php
│ │ └── CurrencyRule.php
│ └── Service/
│ ├── ApiService.php
│ ├── BillableRateService.php
│ ├── BillingContract.php
│ ├── ColorService.php
│ ├── CurrencyService.php
│ ├── DashboardService.php
│ ├── DeletionService.php
│ ├── Dto/
│ │ └── ReportPropertiesDto.php
│ ├── Export/
│ │ ├── ExportException.php
│ │ └── ExportService.php
│ ├── Import/
│ │ ├── ImportDatabaseHelper.php
│ │ ├── ImportService.php
│ │ └── Importers/
│ │ ├── ClockifyProjectsImporter.php
│ │ ├── ClockifyTimeEntriesImporter.php
│ │ ├── DefaultImporter.php
│ │ ├── GenericProjectsImporter.php
│ │ ├── GenericTimeEntriesImporter.php
│ │ ├── HarvestClientsImporter.php
│ │ ├── HarvestProjectsImporter.php
│ │ ├── HarvestTimeEntriesImporter.php
│ │ ├── ImportException.php
│ │ ├── ImporterContract.php
│ │ ├── ImporterProvider.php
│ │ ├── ReportDto.php
│ │ ├── SolidtimeImporter.php
│ │ ├── TogglDataImporter.php
│ │ └── TogglTimeEntriesImporter.php
│ ├── IntervalService.php
│ ├── InvitationService.php
│ ├── IpLookup/
│ │ ├── IpLookupResponseDto.php
│ │ ├── IpLookupServiceContract.php
│ │ └── NoIpLookupService.php
│ ├── LocalizationService.php
│ ├── MemberService.php
│ ├── OrganizationInvitationService.php
│ ├── OrganizationService.php
│ ├── PermissionStore.php
│ ├── ReportExport/
│ │ ├── CsvExport.php
│ │ ├── TimeEntriesDetailedCsvExport.php
│ │ ├── TimeEntriesDetailedExport.php
│ │ └── TimeEntriesReportExport.php
│ ├── ReportService.php
│ ├── TimeEntryAggregationService.php
│ ├── TimeEntryFilter.php
│ ├── TimeEntryService.php
│ ├── TimezoneService.php
│ └── UserService.php
├── artisan
├── bootstrap/
│ ├── app.php
│ └── cache/
│ └── .gitignore
├── components.json
├── composer.json
├── config/
│ ├── app.php
│ ├── audit.php
│ ├── auth.php
│ ├── broadcasting.php
│ ├── cache.php
│ ├── cors.php
│ ├── database.php
│ ├── excel.php
│ ├── filament.php
│ ├── filesystems.php
│ ├── fortify.php
│ ├── hashing.php
│ ├── jetstream.php
│ ├── logging.php
│ ├── mail.php
│ ├── modules.php
│ ├── octane.php
│ ├── passport.php
│ ├── queue.php
│ ├── scheduling.php
│ ├── scramble.php
│ ├── services.php
│ ├── session.php
│ ├── telescope.php
│ ├── trustedproxy.php
│ └── view.php
├── database/
│ ├── .gitignore
│ ├── factories/
│ │ ├── AuditFactory.php
│ │ ├── ClientFactory.php
│ │ ├── FailedJobFactory.php
│ │ ├── MemberFactory.php
│ │ ├── OrganizationFactory.php
│ │ ├── OrganizationInvitationFactory.php
│ │ ├── Passport/
│ │ │ ├── ClientFactory.php
│ │ │ └── TokenFactory.php
│ │ ├── ProjectFactory.php
│ │ ├── ProjectMemberFactory.php
│ │ ├── ReportFactory.php
│ │ ├── TagFactory.php
│ │ ├── TaskFactory.php
│ │ ├── TimeEntryFactory.php
│ │ └── UserFactory.php
│ ├── migrations/
│ │ ├── 2014_10_12_000000_create_users_table.php
│ │ ├── 2014_10_12_100000_create_password_reset_tokens_table.php
│ │ ├── 2014_10_12_200000_add_two_factor_columns_to_users_table.php
│ │ ├── 2016_06_01_000001_create_oauth_auth_codes_table.php
│ │ ├── 2016_06_01_000002_create_oauth_access_tokens_table.php
│ │ ├── 2016_06_01_000003_create_oauth_refresh_tokens_table.php
│ │ ├── 2016_06_01_000004_create_oauth_clients_table.php
│ │ ├── 2016_06_01_000005_create_oauth_personal_access_clients_table.php
│ │ ├── 2018_08_08_100000_create_telescope_entries_table.php
│ │ ├── 2019_08_19_000000_create_failed_jobs_table.php
│ │ ├── 2019_12_14_000001_create_personal_access_tokens_table.php
│ │ ├── 2020_05_21_100000_create_organizations_table.php
│ │ ├── 2020_05_21_200000_create_organization_user_table.php
│ │ ├── 2020_05_21_300000_create_organization_invitations_table.php
│ │ ├── 2024_01_16_161030_create_sessions_table.php
│ │ ├── 2024_01_20_110218_create_clients_table.php
│ │ ├── 2024_01_20_110439_create_projects_table.php
│ │ ├── 2024_01_20_110444_create_tasks_table.php
│ │ ├── 2024_01_20_110452_create_tags_table.php
│ │ ├── 2024_01_20_110837_create_time_entries_table.php
│ │ ├── 2024_03_26_171253_create_project_members_table.php
│ │ ├── 2024_04_11_150130_create_jobs_table.php
│ │ ├── 2024_04_12_095010_create_cache_table.php
│ │ ├── 2024_05_07_134711_move_from_user_id_to_member_id_in_project_members_table.php
│ │ ├── 2024_05_07_141842_move_from_user_id_to_member_id_in_time_entries_table.php
│ │ ├── 2024_05_13_171020_rename_table_organization_user_to_members.php
│ │ ├── 2024_05_22_151226_add_client_id_to_time_entries_table.php
│ │ ├── 2024_05_30_175801_add_is_billable_column_to_projects_table.php
│ │ ├── 2024_05_30_175825_add_is_imported_column_to_time_entries_table.php
│ │ ├── 2024_06_01_000001_create_oauth_device_codes_table.php
│ │ ├── 2024_06_07_113443_change_member_id_foreign_keys_to_restrict_on_delete.php
│ │ ├── 2024_06_10_161831_reset_billable_rates_with_zero_as_value.php
│ │ ├── 2024_06_21_122754_add_is_archived_columns_to_projects_and_clients_table.php
│ │ ├── 2024_06_24_114433_add_done_at_to_tasks_table.php
│ │ ├── 2024_07_02_134307_add_estimated_time_to_projects_and_tasks_table.php
│ │ ├── 2024_07_03_145445_change_data_type_of_id_column_in_failed_jobs_table.php
│ │ ├── 2024_07_18_080906_add_still_active_email_sent_at_to_time_entries_table.php
│ │ ├── 2024_08_01_104840_create_reports_table.php
│ │ ├── 2024_09_02_094105_create_audits_table.php
│ │ ├── 2024_09_18_120203_add_spent_time_to_projects_and_tasks_table.php
│ │ ├── 2024_10_01_143608_add_employees_can_see_billable_rates_to_organizations_table.php
│ │ ├── 2024_11_04_164807_add_foreign_key_to_organizations_and_members_table.php
│ │ ├── 2024_11_04_170614_add_foreign_keys_to_oauth_tables.php
│ │ ├── 2025_04_03_101827_add_localization_columns_to_organizations_table.php
│ │ ├── 2025_04_25_202047_change_data_type_for_spent_time_columns.php
│ │ ├── 2025_05_06_152804_fix_typos_in_organizations_table_format_columns.php
│ │ ├── 2025_05_16_075757_add_foreign_key_for_current_team_id_in_users_table.php
│ │ ├── 2025_06_30_095942_remove_oauth_personal_access_clients_table.php
│ │ ├── 2025_06_30_132538_update_oauth_clients_table.php
│ │ ├── 2025_07_15_105949_hash_oauth_clients.php
│ │ ├── 2025_07_17_104903_add_reminder_sent_at_to_oauth_access_tokens_table.php
│ │ ├── 2025_10_02_000001_add_prevent_overlapping_time_entries_to_organizations_table.php
│ │ ├── 2025_10_16_000001_extend_time_entry_description.php
│ │ └── 2025_10_24_120845_add_employees_can_manage_tasks_to_organizations_table.php
│ ├── schema/
│ │ └── pgsql_test-schema.sql
│ └── seeders/
│ └── DatabaseSeeder.php
├── docker/
│ ├── local/
│ │ ├── 8.3/
│ │ │ ├── Dockerfile
│ │ │ ├── php.ini
│ │ │ ├── start-container
│ │ │ └── supervisord.conf
│ │ ├── minio/
│ │ │ └── create_bucket.sh
│ │ └── pgsql/
│ │ └── create-testing-database.sql
│ └── prod/
│ ├── Dockerfile
│ ├── LICENSE
│ └── deployment/
│ ├── healthcheck
│ ├── octane/
│ │ └── FrankenPHP/
│ │ ├── Caddyfile
│ │ └── supervisord.frankenphp.conf
│ ├── php.ini
│ ├── start-container
│ ├── supervisord.conf
│ ├── supervisord.horizon.conf
│ ├── supervisord.reverb.conf
│ ├── supervisord.scheduler.conf
│ └── supervisord.worker.conf
├── docker-compose.yml
├── e2e/
│ ├── auth.spec.ts
│ ├── calendar-settings.spec.ts
│ ├── calendar.spec.ts
│ ├── clients.spec.ts
│ ├── command-palette.spec.ts
│ ├── dashboard.spec.ts
│ ├── import-export.spec.ts
│ ├── members.spec.ts
│ ├── organization.spec.ts
│ ├── profile.spec.ts
│ ├── project-members.spec.ts
│ ├── projects.spec.ts
│ ├── reporting-detailed.spec.ts
│ ├── reporting.spec.ts
│ ├── shared-reports.spec.ts
│ ├── tags.spec.ts
│ ├── tasks.spec.ts
│ ├── time.spec.ts
│ ├── timetracker.spec.ts
│ └── utils/
│ ├── api.ts
│ ├── currentTimeEntry.ts
│ ├── mailpit.ts
│ ├── members.ts
│ ├── money.ts
│ ├── reporting.ts
│ ├── table.ts
│ └── tags.ts
├── eslint.config.mjs
├── jsconfig.json
├── lang/
│ └── en/
│ ├── auth.php
│ ├── enum.php
│ ├── exceptions.php
│ ├── importer.php
│ ├── pagination.php
│ ├── passwords.php
│ └── validation.php
├── openapi.json
├── package.json
├── phpstan.neon
├── phpunit.xml
├── pint.json
├── playwright/
│ ├── config.ts
│ └── fixtures.ts
├── playwright.config.ts
├── postcss.config.js
├── public/
│ ├── .htaccess
│ ├── desktop-version/
│ │ ├── latest-linux.yml
│ │ ├── latest-mac.yml
│ │ └── latest.yml
│ ├── favicons/
│ │ ├── browserconfig.xml
│ │ └── site.webmanifest
│ ├── index.php
│ ├── robots.txt
│ └── security.txt
├── resources/
│ ├── css/
│ │ ├── app.css
│ │ └── filament/
│ │ └── admin/
│ │ ├── tailwind.config.js
│ │ └── theme.css
│ ├── js/
│ │ ├── Components/
│ │ │ ├── ActionMessage.vue
│ │ │ ├── ActionSection.vue
│ │ │ ├── ApplicationLogo.vue
│ │ │ ├── ApplicationMark.vue
│ │ │ ├── AuthenticationCard.vue
│ │ │ ├── AuthenticationCardLogo.vue
│ │ │ ├── Banner.vue
│ │ │ ├── Billing/
│ │ │ │ └── BillingBanner.vue
│ │ │ ├── CommandPalette/
│ │ │ │ ├── CommandPaletteProvider.vue
│ │ │ │ └── index.ts
│ │ │ ├── Common/
│ │ │ │ ├── Card.vue
│ │ │ │ ├── Client/
│ │ │ │ │ ├── ClientCreateModal.vue
│ │ │ │ │ ├── ClientEditModal.vue
│ │ │ │ │ ├── ClientMoreOptionsDropdown.vue
│ │ │ │ │ ├── ClientMultiselectDropdown.vue
│ │ │ │ │ ├── ClientTable.vue
│ │ │ │ │ ├── ClientTableHeading.vue
│ │ │ │ │ └── ClientTableRow.vue
│ │ │ │ ├── Invitation/
│ │ │ │ │ ├── InvitationMoreOptionsDropdown.vue
│ │ │ │ │ ├── InvitationTable.vue
│ │ │ │ │ ├── InvitationTableHeading.vue
│ │ │ │ │ └── InvitationTableRow.vue
│ │ │ │ ├── Member/
│ │ │ │ │ ├── MemberBillableRateModal.vue
│ │ │ │ │ ├── MemberBillableSelect.vue
│ │ │ │ │ ├── MemberCombobox.vue
│ │ │ │ │ ├── MemberDeleteModal.vue
│ │ │ │ │ ├── MemberEditModal.vue
│ │ │ │ │ ├── MemberInviteModal.vue
│ │ │ │ │ ├── MemberMakePlaceholderModal.vue
│ │ │ │ │ ├── MemberMergeModal.vue
│ │ │ │ │ ├── MemberMoreOptionsDropdown.vue
│ │ │ │ │ ├── MemberMultiselectDropdown.vue
│ │ │ │ │ ├── MemberOwnershipTransferConfirmModal.vue
│ │ │ │ │ ├── MemberRoleSelect.vue
│ │ │ │ │ ├── MemberTable.vue
│ │ │ │ │ ├── MemberTableHeading.vue
│ │ │ │ │ └── MemberTableRow.vue
│ │ │ │ ├── Notification/
│ │ │ │ │ └── Notification.vue
│ │ │ │ ├── Organization/
│ │ │ │ │ └── OrganizationBillableRateModal.vue
│ │ │ │ ├── PageTitle.vue
│ │ │ │ ├── Project/
│ │ │ │ │ ├── BaseFilterBadge.vue
│ │ │ │ │ ├── ProjectClientFilterBadge.vue
│ │ │ │ │ ├── ProjectDropdown.vue
│ │ │ │ │ ├── ProjectEditModal.vue
│ │ │ │ │ ├── ProjectMoreOptionsDropdown.vue
│ │ │ │ │ ├── ProjectMultiselectDropdown.vue
│ │ │ │ │ ├── ProjectStatusFilterBadge.vue
│ │ │ │ │ ├── ProjectTable.vue
│ │ │ │ │ ├── ProjectTableHeading.vue
│ │ │ │ │ ├── ProjectTableRow.vue
│ │ │ │ │ ├── ProjectsFilterDropdown.vue
│ │ │ │ │ └── constants.ts
│ │ │ │ ├── ProjectMember/
│ │ │ │ │ ├── ProjectMemberBillableRateModal.vue
│ │ │ │ │ ├── ProjectMemberCreateModal.vue
│ │ │ │ │ ├── ProjectMemberEditModal.vue
│ │ │ │ │ ├── ProjectMemberMoreOptionsDropdown.vue
│ │ │ │ │ ├── ProjectMemberTable.vue
│ │ │ │ │ ├── ProjectMemberTableHeading.vue
│ │ │ │ │ └── ProjectMemberTableRow.vue
│ │ │ │ ├── Report/
│ │ │ │ │ ├── ReportCreateModal.vue
│ │ │ │ │ ├── ReportEditModal.vue
│ │ │ │ │ ├── ReportMoreOptionsDropdown.vue
│ │ │ │ │ ├── ReportSaveButton.vue
│ │ │ │ │ ├── ReportTable.vue
│ │ │ │ │ ├── ReportTableHeading.vue
│ │ │ │ │ └── ReportTableRow.vue
│ │ │ │ ├── Reporting/
│ │ │ │ │ ├── ReportingChart.vue
│ │ │ │ │ ├── ReportingExportButton.vue
│ │ │ │ │ ├── ReportingExportModal.vue
│ │ │ │ │ ├── ReportingFilterBadge.vue
│ │ │ │ │ ├── ReportingFilterBar.vue
│ │ │ │ │ ├── ReportingGroupBySelect.vue
│ │ │ │ │ ├── ReportingOverview.vue
│ │ │ │ │ ├── ReportingPieChart.vue
│ │ │ │ │ ├── ReportingRoundingControls.vue
│ │ │ │ │ ├── ReportingRow.vue
│ │ │ │ │ └── ReportingTabNavbar.vue
│ │ │ │ ├── StatCard.vue
│ │ │ │ ├── TabBar/
│ │ │ │ │ ├── TabBar.vue
│ │ │ │ │ └── TabBarItem.vue
│ │ │ │ ├── TableHeading.vue
│ │ │ │ ├── Tag/
│ │ │ │ │ ├── TagEditModal.vue
│ │ │ │ │ ├── TagMoreOptionsDropdown.vue
│ │ │ │ │ ├── TagTable.vue
│ │ │ │ │ ├── TagTableHeading.vue
│ │ │ │ │ └── TagTableRow.vue
│ │ │ │ ├── Task/
│ │ │ │ │ ├── TaskCreateModal.vue
│ │ │ │ │ ├── TaskEditModal.vue
│ │ │ │ │ ├── TaskMoreOptionsDropdown.vue
│ │ │ │ │ ├── TaskMultiselectDropdown.vue
│ │ │ │ │ ├── TaskTable.vue
│ │ │ │ │ ├── TaskTableHeading.vue
│ │ │ │ │ └── TaskTableRow.vue
│ │ │ │ ├── UpgradeBadge.vue
│ │ │ │ ├── UpgradeModal.vue
│ │ │ │ └── User/
│ │ │ │ └── UserTimezoneMismatchModal.vue
│ │ │ ├── ConfirmationModal.vue
│ │ │ ├── ConfirmsPassword.vue
│ │ │ ├── CurrentSidebarTimer.vue
│ │ │ ├── Dashboard/
│ │ │ │ ├── ActivityGraphCard.vue
│ │ │ │ ├── DashboardCard.vue
│ │ │ │ ├── DayOverviewCardChart.vue
│ │ │ │ ├── DayOverviewCardEntry.vue
│ │ │ │ ├── LastSevenDaysCard.vue
│ │ │ │ ├── ProjectsChartCard.vue
│ │ │ │ ├── RecentlyTrackedTasksCard.vue
│ │ │ │ ├── RecentlyTrackedTasksCardEntry.vue
│ │ │ │ ├── TeamActivityCard.vue
│ │ │ │ ├── TeamActivityCardEntry.vue
│ │ │ │ ├── ThisWeekOverview.vue
│ │ │ │ └── ThisWeekReportingTable.vue
│ │ │ ├── DropdownLink.vue
│ │ │ ├── FormSection.vue
│ │ │ ├── NavLink.vue
│ │ │ ├── NavigationSidebarItem.vue
│ │ │ ├── NavigationSidebarLink.vue
│ │ │ ├── NotificationContainer.vue
│ │ │ ├── OrganizationSwitcher.vue
│ │ │ ├── ResponsiveNavLink.vue
│ │ │ ├── SectionBorder.vue
│ │ │ ├── SectionTitle.vue
│ │ │ ├── TableRow.vue
│ │ │ ├── TimeTracker.vue
│ │ │ ├── UpdateSidebarNotification.vue
│ │ │ ├── UserSettingsIcon.vue
│ │ │ └── ui/
│ │ │ ├── alert-dialog/
│ │ │ │ ├── AlertDialog.vue
│ │ │ │ ├── AlertDialogAction.vue
│ │ │ │ ├── AlertDialogCancel.vue
│ │ │ │ ├── AlertDialogContent.vue
│ │ │ │ ├── AlertDialogDescription.vue
│ │ │ │ ├── AlertDialogFooter.vue
│ │ │ │ ├── AlertDialogHeader.vue
│ │ │ │ ├── AlertDialogTitle.vue
│ │ │ │ ├── AlertDialogTrigger.vue
│ │ │ │ └── index.ts
│ │ │ ├── calendar/
│ │ │ │ ├── Calendar.vue
│ │ │ │ ├── CalendarCell.vue
│ │ │ │ ├── CalendarCellTrigger.vue
│ │ │ │ ├── CalendarDateInput.vue
│ │ │ │ ├── CalendarGrid.vue
│ │ │ │ ├── CalendarGridBody.vue
│ │ │ │ ├── CalendarGridHead.vue
│ │ │ │ ├── CalendarGridRow.vue
│ │ │ │ ├── CalendarHeadCell.vue
│ │ │ │ ├── CalendarHeader.vue
│ │ │ │ ├── CalendarHeading.vue
│ │ │ │ ├── CalendarNextButton.vue
│ │ │ │ ├── CalendarPrevButton.vue
│ │ │ │ └── index.ts
│ │ │ ├── dialog/
│ │ │ │ ├── Dialog.vue
│ │ │ │ ├── DialogClose.vue
│ │ │ │ ├── DialogContent.vue
│ │ │ │ ├── DialogDescription.vue
│ │ │ │ ├── DialogFooter.vue
│ │ │ │ ├── DialogHeader.vue
│ │ │ │ ├── DialogScrollContent.vue
│ │ │ │ ├── DialogTitle.vue
│ │ │ │ ├── DialogTrigger.vue
│ │ │ │ └── index.ts
│ │ │ ├── dropdown-menu/
│ │ │ │ ├── DropdownMenu.vue
│ │ │ │ ├── DropdownMenuCheckboxItem.vue
│ │ │ │ ├── DropdownMenuContent.vue
│ │ │ │ ├── DropdownMenuGroup.vue
│ │ │ │ ├── DropdownMenuItem.vue
│ │ │ │ ├── DropdownMenuLabel.vue
│ │ │ │ ├── DropdownMenuRadioGroup.vue
│ │ │ │ ├── DropdownMenuRadioItem.vue
│ │ │ │ ├── DropdownMenuSeparator.vue
│ │ │ │ ├── DropdownMenuShortcut.vue
│ │ │ │ ├── DropdownMenuSub.vue
│ │ │ │ ├── DropdownMenuSubContent.vue
│ │ │ │ ├── DropdownMenuSubTrigger.vue
│ │ │ │ ├── DropdownMenuTrigger.vue
│ │ │ │ └── index.ts
│ │ │ ├── label/
│ │ │ │ ├── Label.vue
│ │ │ │ └── index.ts
│ │ │ ├── number-field/
│ │ │ │ ├── NumberField.vue
│ │ │ │ ├── NumberFieldContent.vue
│ │ │ │ ├── NumberFieldDecrement.vue
│ │ │ │ ├── NumberFieldIncrement.vue
│ │ │ │ ├── NumberFieldInput.vue
│ │ │ │ └── index.ts
│ │ │ ├── select/
│ │ │ │ ├── Select.vue
│ │ │ │ ├── SelectContent.vue
│ │ │ │ ├── SelectGroup.vue
│ │ │ │ ├── SelectItem.vue
│ │ │ │ ├── SelectItemText.vue
│ │ │ │ ├── SelectLabel.vue
│ │ │ │ ├── SelectScrollDownButton.vue
│ │ │ │ ├── SelectScrollUpButton.vue
│ │ │ │ ├── SelectSeparator.vue
│ │ │ │ ├── SelectTrigger.vue
│ │ │ │ ├── SelectValue.vue
│ │ │ │ └── index.ts
│ │ │ ├── switch/
│ │ │ │ ├── Switch.vue
│ │ │ │ └── index.ts
│ │ │ ├── table/
│ │ │ │ ├── Table.vue
│ │ │ │ ├── TableBody.vue
│ │ │ │ ├── TableCaption.vue
│ │ │ │ ├── TableCell.vue
│ │ │ │ ├── TableEmpty.vue
│ │ │ │ ├── TableFooter.vue
│ │ │ │ ├── TableHead.vue
│ │ │ │ ├── TableHeader.vue
│ │ │ │ ├── TableRow.vue
│ │ │ │ └── index.ts
│ │ │ └── tabs/
│ │ │ ├── Tabs.vue
│ │ │ ├── TabsContent.vue
│ │ │ ├── TabsList.vue
│ │ │ ├── TabsTrigger.vue
│ │ │ └── index.ts
│ │ ├── Layouts/
│ │ │ └── AppLayout.vue
│ │ ├── Pages/
│ │ │ ├── API/
│ │ │ │ ├── Index.vue
│ │ │ │ └── Partials/
│ │ │ │ └── ApiTokenManager.vue
│ │ │ ├── Auth/
│ │ │ │ ├── ConfirmPassword.vue
│ │ │ │ ├── ForgotPassword.vue
│ │ │ │ ├── Login.vue
│ │ │ │ ├── Register.vue
│ │ │ │ ├── ResetPassword.vue
│ │ │ │ ├── TwoFactorChallenge.vue
│ │ │ │ └── VerifyEmail.vue
│ │ │ ├── Calendar.vue
│ │ │ ├── Clients.vue
│ │ │ ├── Dashboard.vue
│ │ │ ├── Import.vue
│ │ │ ├── Members.vue
│ │ │ ├── PrivacyPolicy.vue
│ │ │ ├── Profile/
│ │ │ │ ├── Partials/
│ │ │ │ │ ├── ApiTokensForm.vue
│ │ │ │ │ ├── DeleteUserForm.vue
│ │ │ │ │ ├── LogoutOtherBrowserSessionsForm.vue
│ │ │ │ │ ├── ThemeForm.vue
│ │ │ │ │ ├── TwoFactorAuthenticationForm.vue
│ │ │ │ │ ├── UpdatePasswordForm.vue
│ │ │ │ │ └── UpdateProfileInformationForm.vue
│ │ │ │ └── Show.vue
│ │ │ ├── ProjectShow.vue
│ │ │ ├── Projects.vue
│ │ │ ├── Reporting.vue
│ │ │ ├── ReportingDetailed.vue
│ │ │ ├── ReportingShared.vue
│ │ │ ├── SharedReport.vue
│ │ │ ├── Tags.vue
│ │ │ ├── Teams/
│ │ │ │ ├── Create.vue
│ │ │ │ ├── Partials/
│ │ │ │ │ ├── CreateTeamForm.vue
│ │ │ │ │ ├── DeleteTeamForm.vue
│ │ │ │ │ ├── ExportData.vue
│ │ │ │ │ ├── ImportData.vue
│ │ │ │ │ ├── OrganizationBillableRate.vue
│ │ │ │ │ ├── OrganizationFormatSettings.vue
│ │ │ │ │ ├── OrganizationTimeEntrySettings.vue
│ │ │ │ │ ├── TeamMemberManager.vue
│ │ │ │ │ └── UpdateTeamNameForm.vue
│ │ │ │ └── Show.vue
│ │ │ ├── TermsOfService.vue
│ │ │ ├── Time.vue
│ │ │ └── Welcome.vue
│ │ ├── app.ts
│ │ ├── bootstrap.js
│ │ ├── lib/
│ │ │ └── utils.ts
│ │ ├── packages/
│ │ │ ├── api/
│ │ │ │ ├── .gitignore
│ │ │ │ ├── package.json
│ │ │ │ ├── src/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── openapi.json.client.ts
│ │ │ │ ├── tsconfig.json
│ │ │ │ └── vite.config.js
│ │ │ └── ui/
│ │ │ ├── .gitignore
│ │ │ ├── package.json
│ │ │ ├── src/
│ │ │ │ ├── Badge.vue
│ │ │ │ ├── BillableRateModal.vue
│ │ │ │ ├── Buttons/
│ │ │ │ │ ├── Button.vue
│ │ │ │ │ ├── DangerButton.vue
│ │ │ │ │ ├── PrimaryButton.vue
│ │ │ │ │ ├── SecondaryButton.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── CardTitle.vue
│ │ │ │ ├── Client/
│ │ │ │ │ ├── ClientDropdown.vue
│ │ │ │ │ └── ClientDropdownItem.vue
│ │ │ │ ├── CommandPalette/
│ │ │ │ │ ├── CommandPalette.vue
│ │ │ │ │ ├── CommandPaletteTypes.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── DialogModal.vue
│ │ │ │ ├── EstimatedTimeProgress.vue
│ │ │ │ ├── EstimatedTimeSection.vue
│ │ │ │ ├── FullCalendar/
│ │ │ │ │ ├── CalendarSettingsPopover.vue
│ │ │ │ │ ├── FullCalendarDayHeader.vue
│ │ │ │ │ ├── FullCalendarEventContent.vue
│ │ │ │ │ ├── TimeEntryCalendar.vue
│ │ │ │ │ ├── calendarSettings.ts
│ │ │ │ │ ├── idleStatusPlugin.ts
│ │ │ │ │ └── useVisualSnap.ts
│ │ │ │ ├── GroupedItemsCountButton.vue
│ │ │ │ ├── Icons/
│ │ │ │ │ ├── BillableIcon.vue
│ │ │ │ │ ├── DollarIcon.vue
│ │ │ │ │ ├── EuroIcon.vue
│ │ │ │ │ └── ListFilterIcon.vue
│ │ │ │ ├── Input/
│ │ │ │ │ ├── BillableRateInput.vue
│ │ │ │ │ ├── BillableToggleButton.vue
│ │ │ │ │ ├── Checkbox.vue
│ │ │ │ │ ├── DatePicker.vue
│ │ │ │ │ ├── DateRangePicker.vue
│ │ │ │ │ ├── Dropdown.vue
│ │ │ │ │ ├── DurationHumanInput.vue
│ │ │ │ │ ├── EstimatedTimeInput.vue
│ │ │ │ │ ├── InputError.vue
│ │ │ │ │ ├── InputLabel.vue
│ │ │ │ │ ├── MultiselectDropdown.vue
│ │ │ │ │ ├── TextInput.vue
│ │ │ │ │ ├── TextareaInput.vue
│ │ │ │ │ ├── TimePickerSimple.vue
│ │ │ │ │ └── TimeRangeSelector.vue
│ │ │ │ ├── LoadingSpinner.vue
│ │ │ │ ├── MainContainer.vue
│ │ │ │ ├── Modal.vue
│ │ │ │ ├── Project/
│ │ │ │ │ ├── ProjectBadge.vue
│ │ │ │ │ ├── ProjectBillableRateModal.vue
│ │ │ │ │ ├── ProjectBillableSelect.vue
│ │ │ │ │ ├── ProjectColorSelector.vue
│ │ │ │ │ ├── ProjectCreateModal.vue
│ │ │ │ │ ├── ProjectDropdownItem.vue
│ │ │ │ │ └── ProjectEditBillableSection.vue
│ │ │ │ ├── Tag/
│ │ │ │ │ ├── TagBadge.vue
│ │ │ │ │ ├── TagCreateModal.vue
│ │ │ │ │ └── TagDropdown.vue
│ │ │ │ ├── TimeEntry/
│ │ │ │ │ ├── TimeEntryAggregateRow.vue
│ │ │ │ │ ├── TimeEntryCreateModal.vue
│ │ │ │ │ ├── TimeEntryDescriptionInput.vue
│ │ │ │ │ ├── TimeEntryEditModal.vue
│ │ │ │ │ ├── TimeEntryGroupedTable.vue
│ │ │ │ │ ├── TimeEntryMassActionRow.vue
│ │ │ │ │ ├── TimeEntryMassUpdateModal.vue
│ │ │ │ │ ├── TimeEntryMoreOptionsDropdown.vue
│ │ │ │ │ ├── TimeEntryRangeSelector.vue
│ │ │ │ │ ├── TimeEntryRow.vue
│ │ │ │ │ ├── TimeEntryRowDurationInput.vue
│ │ │ │ │ ├── TimeEntryRowHeading.vue
│ │ │ │ │ └── TimeEntryRowTagDropdown.vue
│ │ │ │ ├── TimeTracker/
│ │ │ │ │ ├── TimeTrackerControls.vue
│ │ │ │ │ ├── TimeTrackerMoreOptionsDropdown.vue
│ │ │ │ │ ├── TimeTrackerProjectTaskDropdown.vue
│ │ │ │ │ ├── TimeTrackerRangeSelector.vue
│ │ │ │ │ ├── TimeTrackerRecentlyTrackedEntry.vue
│ │ │ │ │ ├── TimeTrackerRunningInDifferentOrganizationOverlay.vue
│ │ │ │ │ └── TimeTrackerTagDropdown.vue
│ │ │ │ ├── TimeTrackerStartStop.vue
│ │ │ │ ├── TimezoneMismatchModal.vue
│ │ │ │ ├── accordion/
│ │ │ │ │ ├── Accordion.vue
│ │ │ │ │ ├── AccordionContent.vue
│ │ │ │ │ ├── AccordionItem.vue
│ │ │ │ │ ├── AccordionTrigger.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── command/
│ │ │ │ │ ├── Command.vue
│ │ │ │ │ ├── CommandGroup.vue
│ │ │ │ │ ├── CommandInput.vue
│ │ │ │ │ ├── CommandItem.vue
│ │ │ │ │ ├── CommandList.vue
│ │ │ │ │ ├── CommandSeparator.vue
│ │ │ │ │ ├── CommandShortcut.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── field/
│ │ │ │ │ ├── Field.vue
│ │ │ │ │ ├── FieldContent.vue
│ │ │ │ │ ├── FieldDescription.vue
│ │ │ │ │ ├── FieldError.vue
│ │ │ │ │ ├── FieldGroup.vue
│ │ │ │ │ ├── FieldLabel.vue
│ │ │ │ │ ├── FieldLegend.vue
│ │ │ │ │ ├── FieldSeparator.vue
│ │ │ │ │ ├── FieldSet.vue
│ │ │ │ │ ├── FieldTitle.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── popover/
│ │ │ │ │ ├── Popover.vue
│ │ │ │ │ ├── PopoverContent.vue
│ │ │ │ │ ├── PopoverTrigger.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── range-calendar/
│ │ │ │ │ ├── RangeCalendar.vue
│ │ │ │ │ ├── RangeCalendarCell.vue
│ │ │ │ │ ├── RangeCalendarCellTrigger.vue
│ │ │ │ │ ├── RangeCalendarGrid.vue
│ │ │ │ │ ├── RangeCalendarGridBody.vue
│ │ │ │ │ ├── RangeCalendarGridHead.vue
│ │ │ │ │ ├── RangeCalendarGridRow.vue
│ │ │ │ │ ├── RangeCalendarHeadCell.vue
│ │ │ │ │ ├── RangeCalendarHeader.vue
│ │ │ │ │ ├── RangeCalendarHeading.vue
│ │ │ │ │ ├── RangeCalendarNextButton.vue
│ │ │ │ │ ├── RangeCalendarPrevButton.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── separator/
│ │ │ │ │ ├── Separator.vue
│ │ │ │ │ └── index.ts
│ │ │ │ ├── tooltip/
│ │ │ │ │ ├── Tooltip.vue
│ │ │ │ │ ├── TooltipContent.vue
│ │ │ │ │ ├── TooltipProvider.vue
│ │ │ │ │ ├── TooltipTrigger.vue
│ │ │ │ │ └── index.ts
│ │ │ │ └── utils/
│ │ │ │ ├── cn.ts
│ │ │ │ ├── color.ts
│ │ │ │ ├── money.ts
│ │ │ │ ├── number.ts
│ │ │ │ ├── random.ts
│ │ │ │ ├── select.ts
│ │ │ │ ├── settings.ts
│ │ │ │ └── time.ts
│ │ │ ├── styles.css
│ │ │ ├── tailwind.theme.js
│ │ │ ├── tsconfig.json
│ │ │ └── vite.config.js
│ │ ├── types/
│ │ │ ├── dom.d.ts
│ │ │ ├── dom.ts
│ │ │ ├── global.d.ts
│ │ │ ├── inertia.d.ts
│ │ │ ├── jetstream.ts
│ │ │ ├── models.d.ts
│ │ │ ├── models.ts
│ │ │ ├── projects.d.ts
│ │ │ ├── reporting.ts
│ │ │ ├── time-entries.d.ts
│ │ │ ├── vite-env.d.ts
│ │ │ └── vue-shim.d.ts
│ │ ├── utils/
│ │ │ ├── billing.ts
│ │ │ ├── commandPaletteCommands.ts
│ │ │ ├── feedback.ts
│ │ │ ├── fetchAllPages.ts
│ │ │ ├── format.ts
│ │ │ ├── init.ts
│ │ │ ├── money.ts
│ │ │ ├── notification.ts
│ │ │ ├── permissions.ts
│ │ │ ├── prefetch.ts
│ │ │ ├── roles.ts
│ │ │ ├── session.ts
│ │ │ ├── theme.ts
│ │ │ ├── useAggregatedTimeEntriesQuery.ts
│ │ │ ├── useClients.ts
│ │ │ ├── useClientsQuery.ts
│ │ │ ├── useCommandPalette.ts
│ │ │ ├── useCssVariable.ts
│ │ │ ├── useCurrentTimeEntry.ts
│ │ │ ├── useInvitations.ts
│ │ │ ├── useMembers.ts
│ │ │ ├── useMembersQuery.ts
│ │ │ ├── useOrganization.ts
│ │ │ ├── useOrganizationQuery.ts
│ │ │ ├── useProjectMembers.ts
│ │ │ ├── useProjectMembersQuery.ts
│ │ │ ├── useProjects.ts
│ │ │ ├── useProjectsQuery.ts
│ │ │ ├── useReporting.ts
│ │ │ ├── useReportsQuery.ts
│ │ │ ├── useTags.ts
│ │ │ ├── useTagsQuery.ts
│ │ │ ├── useTasks.ts
│ │ │ ├── useTasksQuery.ts
│ │ │ ├── useTimeEntriesCalendarQuery.ts
│ │ │ ├── useTimeEntriesInfiniteQuery.ts
│ │ │ ├── useTimeEntriesMutations.ts
│ │ │ ├── useTimeEntriesReportQuery.ts
│ │ │ └── useUser.ts
│ │ ├── ziggy.d.ts
│ │ └── ziggy.js
│ ├── markdown/
│ │ ├── policy.md
│ │ └── terms.md
│ ├── testfiles/
│ │ ├── clockify_projects_import_test_1.csv
│ │ ├── clockify_time_entries_import_test_1.csv
│ │ ├── clockify_time_entries_import_test_2.csv
│ │ ├── clockify_time_entries_import_test_3.csv
│ │ ├── generic_projects_import_test_1.csv
│ │ ├── generic_time_entries_import_test_1.csv
│ │ ├── harvest_clients_import_test_1.csv
│ │ ├── harvest_projects_import_test_1.csv
│ │ ├── harvest_time_entries_import_test_1.csv
│ │ ├── solidtime_import_test_1/
│ │ │ ├── clients.csv
│ │ │ ├── members.csv
│ │ │ ├── meta.json
│ │ │ ├── organization_invitations.csv
│ │ │ ├── organizations.csv
│ │ │ ├── project_members.csv
│ │ │ ├── projects.csv
│ │ │ ├── tags.csv
│ │ │ ├── tasks.csv
│ │ │ └── time_entries.csv
│ │ ├── toggl_data_import_test_1/
│ │ │ ├── clients.json
│ │ │ ├── projects.json
│ │ │ ├── projects_users/
│ │ │ │ ├── 401.json
│ │ │ │ ├── 402.json
│ │ │ │ └── 403.json
│ │ │ ├── tags.json
│ │ │ ├── tasks/
│ │ │ │ ├── 401.json
│ │ │ │ ├── 402.json
│ │ │ │ └── 403.json
│ │ │ └── workspace_users.json
│ │ ├── toggl_data_import_test_2/
│ │ │ ├── clients.json
│ │ │ ├── projects.json
│ │ │ ├── projects_users/
│ │ │ │ ├── 401.json
│ │ │ │ ├── 402.json
│ │ │ │ └── 403.json
│ │ │ ├── tags.json
│ │ │ ├── tasks/
│ │ │ │ ├── 401.json
│ │ │ │ ├── 402.json
│ │ │ │ └── 403.json
│ │ │ └── workspace_users.json
│ │ ├── toggl_time_entries_import_test_1.csv
│ │ └── toggl_time_entries_import_test_2.csv
│ └── views/
│ ├── app.blade.php
│ ├── auth/
│ │ └── oauth/
│ │ └── authorize.blade.php
│ ├── emails/
│ │ ├── auth-api-expiration-reminder.blade.php
│ │ ├── auth-api-token-expired.blade.php
│ │ ├── organization-invitation.blade.php
│ │ └── time-entry-still-running.blade.php
│ ├── filament/
│ │ └── widgets/
│ │ └── server-overview.blade.php
│ ├── reports/
│ │ ├── time-entry-aggregate/
│ │ │ ├── pdf-footer.blade.php
│ │ │ ├── pdf.blade.php
│ │ │ └── spreadsheet.blade.php
│ │ └── time-entry-index/
│ │ ├── pdf-footer.blade.php
│ │ └── pdf.blade.php
│ └── vendor/
│ └── mail/
│ ├── html/
│ │ ├── button.blade.php
│ │ ├── footer.blade.php
│ │ ├── header.blade.php
│ │ ├── layout.blade.php
│ │ ├── message.blade.php
│ │ ├── panel.blade.php
│ │ ├── subcopy.blade.php
│ │ ├── table.blade.php
│ │ └── themes/
│ │ └── default.css
│ └── text/
│ ├── button.blade.php
│ ├── footer.blade.php
│ ├── header.blade.php
│ ├── layout.blade.php
│ ├── message.blade.php
│ ├── panel.blade.php
│ ├── subcopy.blade.php
│ └── table.blade.php
├── routes/
│ ├── api.php
│ └── web.php
├── storage/
│ ├── app/
│ │ └── .gitignore
│ ├── framework/
│ │ ├── .gitignore
│ │ ├── cache/
│ │ │ └── .gitignore
│ │ ├── sessions/
│ │ │ └── .gitignore
│ │ ├── testing/
│ │ │ └── .gitignore
│ │ └── views/
│ │ └── .gitignore
│ └── logs/
│ └── .gitignore
├── tailwind.config.js
├── tests/
│ ├── CreatesApplication.php
│ ├── Feature/
│ │ ├── AuthenticationTest.php
│ │ ├── BrowserSessionsTest.php
│ │ ├── CreateOrganizationTest.php
│ │ ├── DeleteAccountTest.php
│ │ ├── DeleteOrganizationTest.php
│ │ ├── EmailVerificationTest.php
│ │ ├── InviteTeamMemberTest.php
│ │ ├── LeaveTeamTest.php
│ │ ├── PasswordConfirmationTest.php
│ │ ├── PasswordResetTest.php
│ │ ├── ProfileInformationTest.php
│ │ ├── RegistrationTest.php
│ │ ├── RemoveTeamMemberTest.php
│ │ ├── TwoFactorAuthenticationSettingsTest.php
│ │ ├── UpdatePasswordTest.php
│ │ ├── UpdateTeamMemberRoleTest.php
│ │ └── UpdateTeamTest.php
│ ├── TestCase.php
│ ├── TestCaseWithDatabase.php
│ └── Unit/
│ ├── Console/
│ │ ├── Commands/
│ │ │ ├── Admin/
│ │ │ │ ├── OrganizationDeleteCommandTest.php
│ │ │ │ ├── UserCreateCommandCommandTest.php
│ │ │ │ └── UserVerifyCommandTest.php
│ │ │ ├── Auth/
│ │ │ │ └── AuthSendReminderForExpiringApiTokensCommandTest.php
│ │ │ ├── Correction/
│ │ │ │ └── CorrectionPlaceholderMembersCommandTest.php
│ │ │ ├── Report/
│ │ │ │ └── ReportSetExpiredToPrivateCommandTest.php
│ │ │ ├── SelfHost/
│ │ │ │ ├── SelfHostCheckForUpdateCommandTest.php
│ │ │ │ ├── SelfHostDatabaseConsistencyCommandTest.php
│ │ │ │ ├── SelfHostGenerateKeysCommandTest.php
│ │ │ │ └── SelfHostTelemetryCommandTest.php
│ │ │ └── TimeEntry/
│ │ │ └── TimeEntrySendStillRunningMailsCommandTest.php
│ │ └── KernelTest.php
│ ├── Database/
│ │ ├── MigrationTest.php
│ │ └── SeederTest.php
│ ├── Endpoint/
│ │ ├── Api/
│ │ │ └── V1/
│ │ │ ├── ApiEndpointTestAbstract.php
│ │ │ ├── ApiTokenEndpointTest.php
│ │ │ ├── ChartEndpointTest.php
│ │ │ ├── ClientEndpointTest.php
│ │ │ ├── CurrencyEndpointTest.php
│ │ │ ├── ExportEndpointTest.php
│ │ │ ├── ImportEndpointTest.php
│ │ │ ├── InvitationEndpointTest.php
│ │ │ ├── MemberEndpointTest.php
│ │ │ ├── OrganizationEndpointTest.php
│ │ │ ├── ProjectEndpointTest.php
│ │ │ ├── ProjectMemberEndpointTest.php
│ │ │ ├── Public/
│ │ │ │ └── PublicReportEndpointTest.php
│ │ │ ├── ReportEndpointTest.php
│ │ │ ├── TagEndpointTest.php
│ │ │ ├── TaskEndpointTest.php
│ │ │ ├── TimeEntryEndpointTest.php
│ │ │ ├── UserEndpointTest.php
│ │ │ ├── UserMembershipEndpointTest.php
│ │ │ └── UserTimeEntryEndpointTest.php
│ │ └── Web/
│ │ ├── DashboardEndpointTest.php
│ │ ├── EndpointTestAbstract.php
│ │ ├── HealthCheckEndpointTest.php
│ │ └── HomeEndpointTest.php
│ ├── Filament/
│ │ ├── FilamentTestCase.php
│ │ ├── Resources/
│ │ │ ├── AuditResourceTest.php
│ │ │ ├── ClientResourceTest.php
│ │ │ ├── FailedJobResourceTest.php
│ │ │ ├── OrganizationInvitationResourceTest.php
│ │ │ ├── OrganizationResourceTest.php
│ │ │ ├── ProjectResourceTest.php
│ │ │ ├── ReportResourceTest.php
│ │ │ ├── TagResourceTest.php
│ │ │ ├── TaskResourceTest.php
│ │ │ ├── TimeEntryResourceTest.php
│ │ │ ├── TokenResourceTest.php
│ │ │ └── UserResourceTest.php
│ │ └── Widgets/
│ │ └── ServerOverviewWidgetTest.php
│ ├── Jobs/
│ │ ├── RecalculateSpentTimeForProjectTest.php
│ │ ├── RecalculateSpentTimeForTaskTest.php
│ │ └── Test/
│ │ └── TestJobTest.php
│ ├── Mail/
│ │ ├── AuthApiTokenExpirationReminderMailTest.php
│ │ ├── AuthApiTokenExpiredMailTest.php
│ │ ├── OrganizationInvitationMailTest.php
│ │ └── TimeEntryStillRunningMailTest.php
│ ├── Middleware/
│ │ ├── CheckOrganizationBlockedMiddlewareTest.php
│ │ ├── EnsureEmailIsVerifiedMiddlewareTest.php
│ │ ├── ForceHttpsMiddlewareTest.php
│ │ ├── HandleInertiaRequestsMiddlewareTest.php
│ │ └── MiddlewareTestAbstract.php
│ ├── Model/
│ │ ├── ClientModelTest.php
│ │ ├── MemberModelTest.php
│ │ ├── ModelTestAbstract.php
│ │ ├── OrganizationModelTest.php
│ │ ├── Passport/
│ │ │ └── TokenModelTest.php
│ │ ├── ProjectMemberModelTest.php
│ │ ├── ProjectModelTest.php
│ │ ├── ReportModelTest.php
│ │ ├── TagModelTest.php
│ │ ├── TaskModelTest.php
│ │ ├── TimeEntryModelTest.php
│ │ └── UserModelTest.php
│ ├── Rules/
│ │ ├── ColorRuleTest.php
│ │ └── CurrencyRuleTest.php
│ └── Service/
│ ├── BillableRateServiceTest.php
│ ├── CurrencyServiceTest.php
│ ├── DashboardServiceTest.php
│ ├── DeletionServiceTest.php
│ ├── Export/
│ │ └── ExportServiceTest.php
│ ├── Import/
│ │ ├── ImportDatabaseHelperTest.php
│ │ ├── ImportServiceTest.php
│ │ └── Importers/
│ │ ├── ClockifyProjectsImporterTest.php
│ │ ├── ClockifyTimeEntriesImporterTest.php
│ │ ├── GenericProjectsImporterTest.php
│ │ ├── GenericTimeEntriesImporterTest.php
│ │ ├── HarvestClientsImporterTest.php
│ │ ├── HarvestProjectsImporterTest.php
│ │ ├── HarvestTimeEntriesImporterTest.php
│ │ ├── ImporterProviderTest.php
│ │ ├── ImporterTestAbstract.php
│ │ ├── SolidtimeImporterTest.php
│ │ ├── TogglDataImporterTest.php
│ │ └── TogglTimeEntriesImporterTest.php
│ ├── IntervalServiceTest.php
│ ├── LocalizationServiceTest.php
│ ├── MemberServiceTest.php
│ ├── PermissionStoreTest.php
│ ├── TimeEntryAggregationServiceTest.php
│ ├── TimeEntryFilterTest.php
│ ├── TimezoneServiceTest.php
│ └── UserServiceTest.php
├── tsconfig.json
├── vite-module-loader.js
└── vite.config.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .editorconfig
================================================
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.{yml,yaml}]
indent_size = 2
[docker-compose.yml]
indent_size = 4
================================================
FILE: .gitattributes
================================================
* text=auto eol=lf
*.blade.php diff=html
*.css diff=css
*.html diff=html
*.md diff=markdown
*.php diff=php
/.github export-ignore
CHANGELOG.md export-ignore
.styleci.yml export-ignore
================================================
FILE: .github/FUNDING.yml
================================================
github: solidtime-io
================================================
FILE: .github/ISSUE_TEMPLATE/1_bug_report.yml
================================================
name: Bug Report
description: "Report a bug"
body:
- type: markdown
attributes:
value: |
Before creating a new bug report, please check that there isn't already a similar issue.
- type: textarea
attributes:
label: Description
description: A clear and concise description of what the bug is.
validations:
required: true
- type: textarea
attributes:
label: "Steps To Reproduce"
description: How do you trigger this bug? Please walk us through it step by step.
value: |
1.
2.
3.
...
validations:
required: false
- type: dropdown
attributes:
label: "Self-hosted or Cloud?"
options:
- Self-Hosted
- solidtime Cloud
- Both
- type: input
attributes:
label: "Version of solidtime: (for self-hosted)"
validations:
required: false
- type: input
attributes:
label: "solidtime self-hosting guide: (for self-hosted)"
description: "Did you use the official guide to self-host solidtime? If yes, which one?"
validations:
required: false
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
- name: 🚀 Feature Request
url: https://github.com/solidtime-io/solidtime/discussions/new?category=feature-requests
about: Share ideas for new features
- name: ❓ Ask a Question
url: https://github.com/solidtime-io/solidtime/discussions/new?category=general
about: Ask the community for help
================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
## What does this PR do?
<!-- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. -->
- Fixes #XXXX (GitHub issue number)
## Checklist (DO NOT REMOVE)
- [ ] I read the [contributing guide](https://github.com/solidtime-io/solidtime/blob/main/CONTRIBUTING.md)
- [ ] I signed the [Contributor License Agreement](https://cla-assistant.io/solidtime-io/solidtime).
- [ ] I commented my code, particularly in hard-to-understand areas
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
target-branch: "main"
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "daily"
target-branch: "main"
- package-ecosystem: "composer"
directory: "/"
schedule:
interval: "weekly"
target-branch: "main"
groups:
major-updates:
update-types:
- "major"
minor-updates:
update-types:
- "minor"
- "patch"
security-updates:
applies-to: version-updates
update-types:
- "minor"
- "patch"
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
target-branch: "main"
groups:
major-updates:
update-types:
- "major"
minor-updates:
update-types:
- "minor"
- "patch"
security-updates:
applies-to: version-updates
update-types:
- "minor"
- "patch"
================================================
FILE: .github/workflows/build-onpremise.yml
================================================
on:
push:
branches:
- main
- develop
tags:
- '*'
pull_request:
paths:
- '.github/workflows/build-onpremise.yml'
- 'docker/prod/**'
workflow_dispatch:
permissions:
packages: write
contents: read
attestations: write
id-token: write
env:
DOCKER_REPO: registry.on-premise.solidtime.io/solidtime/solidtime
name: Build - On Premise
jobs:
build:
strategy:
matrix:
include:
- runs-on: "ubuntu-24.04-arm"
platform: "linux/arm64"
- runs-on: "ubuntu-24.04"
platform: "linux/amd64"
runs-on: ${{ matrix.runs-on }}
timeout-minutes: 90
steps:
- name: "Check out code"
uses: actions/checkout@v4
with:
fetch-depth: 0 # Required for WyriHaximus/github-action-get-previous-tag
- name: "Get build"
id: release-build
run: echo "build=$(git rev-parse --short=8 HEAD)" >> "$GITHUB_OUTPUT"
- name: "Get Previous tag (normal push)"
id: previoustag
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
uses: "WyriHaximus/github-action-get-previous-tag@v1"
with:
prefix: "v"
- name: "Get version"
id: release-version
run: |
if ${{ !startsWith(github.ref, 'refs/tags/v') }}; then
if ${{ startsWith(steps.previoustag.outputs.tag, 'v') }}; then
version=$(echo "${{ steps.previoustag.outputs.tag }}" | cut -c 2-)
echo "app_version=${version}" >> "$GITHUB_OUTPUT"
else
echo "ERROR: No previous tag found";
exit 1;
fi
else
version=$(echo "${{ github.ref }}" | cut -c 12-)
echo "app_version=${version}" >> "$GITHUB_OUTPUT"
fi
- name: "Copy .env template for production"
run: |
cp .env.production .env
rm .env.production .env.ci .env.example
- name: "Add version to .env"
run: sed -i 's/APP_VERSION=0.0.0/APP_VERSION=${{ steps.release-version.outputs.app_version }}/g' .env
- name: "Add build to .env"
run: sed -i 's/APP_BUILD=0/APP_BUILD=${{ steps.release-build.outputs.build }}/g' .env
- name: "Output .env"
run: cat .env
- name: "Setup PHP with PECL extension"
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: mbstring, dom, fileinfo, pgsql
- name: "Install dependencies"
run: composer install --no-dev --no-ansi --no-interaction --prefer-dist --ignore-platform-reqs --classmap-authoritative
if: steps.cache-vendor.outputs.cache-hit != 'true' # Skip if cache hit
- name: "Use Node.js"
uses: actions/setup-node@v4
with:
node-version: '20.x'
- name: "Checkout invoicing extension"
uses: actions/checkout@v4
with:
repository: solidtime-io/extension-invoicing
path: extensions/Invoicing
ssh-key: ${{ secrets.SSH_PRIVATE_KEY_INVOICING_EXTENSION }}
- name: "Install composer dependencies in invoicing extension"
run: cd extensions/Invoicing && composer install --no-dev --no-ansi --no-interaction --prefer-dist --ignore-platform-reqs --classmap-authoritative
- name: "Install npm dependencies in invoicing extension"
run: cd extensions/Invoicing && npm ci
- name: "Activate invoicing extension"
run: php artisan module:enable Invoicing
- name: "Install npm dependencies"
run: npm ci
- name: "Build"
run: npm run build
- name: "Prepare"
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: "Docker meta"
id: "meta"
uses: docker/metadata-action@v5
with:
images: |
${{ env.DOCKER_REPO }}
- name: "Login to solidtime OnPremise Registry"
uses: docker/login-action@v3
with:
registry: registry.on-premise.solidtime.io
username: ${{ secrets.ONPREMISE_USERNAME }}
password: ${{ secrets.ONPREMISE_TOKEN }}
- name: "Set up QEMU"
uses: docker/setup-qemu-action@v3
- name: "Set up Docker Buildx"
uses: docker/setup-buildx-action@v3
- name: "Build and push by digest"
id: build
uses: docker/build-push-action@v6
with:
context: .
file: docker/prod/Dockerfile
build-args: |
DOCKER_FILES_BASE_PATH=docker/prod/
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,"name=${{ env.DOCKER_REPO }}",push-by-digest=true,name-canonical=true,push=true
cache-from: type=gha
cache-to: type=gha,mode=max
- name: "Export digest"
run: |
mkdir -p ${{ runner.temp }}/digests
digest="${{ steps.build.outputs.digest }}"
touch "${{ runner.temp }}/digests/${digest#sha256:}"
- name: "Upload digest"
uses: actions/upload-artifact@v4
with:
name: digests-${{ env.PLATFORM_PAIR }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1
merge:
runs-on: ubuntu-latest
timeout-minutes: 90
needs:
- build
steps:
- name: "Download digests"
uses: actions/download-artifact@v4
with:
path: ${{ runner.temp }}/digests
pattern: digests-*
merge-multiple: true
- name: "Login to solidtime OnPremise Registry"
uses: docker/login-action@v3
with:
registry: registry.on-premise.solidtime.io
username: ${{ secrets.ONPREMISE_USERNAME }}
password: ${{ secrets.ONPREMISE_TOKEN }}
- name: "Set up Docker Buildx"
uses: docker/setup-buildx-action@v3
- name: "Docker meta"
id: meta
uses: docker/metadata-action@v5
with:
images: |
${{ env.DOCKER_REPO }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- name: "Create manifest list and push"
working-directory: ${{ runner.temp }}/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.DOCKER_REPO }}@sha256:%s ' *)
- name: "Inspect image"
run: |
docker buildx imagetools inspect ${{ env.DOCKER_REPO }}:${{ steps.meta.outputs.version }}
================================================
FILE: .github/workflows/build-private.yml
================================================
on:
push:
branches:
- main
- develop
tags:
- '*'
pull_request:
paths:
- '.github/workflows/build-private.yml'
- 'docker/prod/**'
workflow_dispatch:
permissions:
contents: read
name: Build - Private
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: "Check out code"
uses: actions/checkout@v4
with:
fetch-depth: 0 # Required for WyriHaximus/github-action-get-previous-tag
- name: "Get build"
id: build
run: echo "build=$(git rev-parse --short=8 HEAD)" >> "$GITHUB_OUTPUT"
- name: "Get Previous tag (normal push)"
id: previoustag
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
uses: "WyriHaximus/github-action-get-previous-tag@v1"
with:
prefix: "v"
- name: "Get version"
id: version
run: |
if ${{ !startsWith(github.ref, 'refs/tags/v') }}; then
if ${{ startsWith(steps.previoustag.outputs.tag, 'v') }}; then
version=$(echo "${{ steps.previoustag.outputs.tag }}" | cut -c 2-)
echo "app_version=${version}" >> "$GITHUB_OUTPUT"
else
echo "ERROR: No previous tag found";
exit 1;
fi
else
version=$(echo "${{ github.ref }}" | cut -c 12-)
echo "app_version=${version}" >> "$GITHUB_OUTPUT"
fi
- name: "Copy .env template for production"
run: |
cp .env.production .env
rm .env.production .env.ci .env.example
- name: "Add version to .env"
run: sed -i 's/APP_VERSION=0.0.0/APP_VERSION=${{ steps.version.outputs.app_version }}/g' .env
- name: "Add build to .env"
run: sed -i 's/APP_BUILD=0/APP_BUILD=${{ steps.build.outputs.build }}/g' .env
- name: "Output .env"
run: cat .env
- name: "Use Node.js"
uses: actions/setup-node@v4
with:
node-version: '20.x'
- name: "Checkout billing extension"
uses: actions/checkout@v4
with:
repository: solidtime-io/extension-billing
path: extensions/Billing
ssh-key: ${{ secrets.SSH_PRIVATE_KEY_BILLING_EXTENSION }}
- name: "Install dependencies in billing extension"
uses: php-actions/composer@v6
env:
COMPOSER_AUTH: '{"http-basic": {"spark.laravel.com": {"username": "gregor@vostrak.at", "password": "${{ secrets.LARAVEL_SPARK_API_KEY }}"}}}'
with:
working_dir: "extensions/Billing"
command: install
only_args: --no-dev --no-ansi --no-interaction --prefer-dist --ignore-platform-reqs --classmap-authoritative
php_version: 8.3
- name: "Install npm dependencies in billing extension"
run: cd extensions/Billing && npm ci
- name: "Checkout services extension"
uses: actions/checkout@v4
with:
repository: solidtime-io/extension-services
path: extensions/Services
ssh-key: ${{ secrets.SSH_PRIVATE_KEY_SERVICES_EXTENSION }}
- name: "Install composer dependencies in services extension"
uses: php-actions/composer@v6
with:
working_dir: "extensions/Services"
command: install
only_args: --no-dev --no-ansi --no-interaction --prefer-dist --ignore-platform-reqs --classmap-authoritative
php_version: 8.3
- name: "Install npm dependencies in services extension"
run: cd extensions/Services && npm ci
- name: "Checkout invoicing extension"
uses: actions/checkout@v4
with:
repository: solidtime-io/extension-invoicing
path: extensions/Invoicing
ssh-key: ${{ secrets.SSH_PRIVATE_KEY_INVOICING_EXTENSION }}
- name: "Install composer dependencies in invoicing extension"
uses: php-actions/composer@v6
with:
working_dir: "extensions/Invoicing"
command: install
only_args: --no-dev --no-ansi --no-interaction --prefer-dist --ignore-platform-reqs --classmap-authoritative
php_version: 8.3
- name: "Install npm dependencies in invoicing extension"
run: cd extensions/Invoicing && npm ci
- name: "Setup PHP with PECL extension"
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: mbstring, dom, fileinfo, pgsql
- name: "Install dependencies"
uses: php-actions/composer@v6
if: steps.cache-vendor.outputs.cache-hit != 'true' # Skip if cache hit
with:
command: install
only_args: --no-dev --no-ansi --no-interaction --prefer-dist --ignore-platform-reqs --classmap-authoritative
php_version: 8.3
- name: "Activate billing extension"
run: php artisan module:enable Billing
- name: "Activate services extension"
run: php artisan module:enable Services
- name: "Activate invoicing extension"
run: php artisan module:enable Invoicing
- name: "Install npm dependencies"
run: npm ci
- name: "Build"
run: npm run build
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
- name: "Login to GitHub Container Registry"
uses: docker/login-action@v3
with:
registry: rg.fr-par.scw.cloud/solidtime
username: nologin
password: ${{ secrets.SCALEWAY_REGISTRY_TOKEN }}
- name: "Docker meta"
id: "meta"
uses: docker/metadata-action@v5
with:
images: rg.fr-par.scw.cloud/solidtime/solidtime
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,format=long
- name: "Set up QEMU"
uses: docker/setup-qemu-action@v3
- name: "Set up Docker Buildx"
uses: docker/setup-buildx-action@v3
- name: "Build and push"
uses: docker/build-push-action@v6
with:
context: .
build-args: |
DOCKER_FILES_BASE_PATH=docker/prod/
file: docker/prod/Dockerfile
push: true
platforms: linux/amd64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
================================================
FILE: .github/workflows/build-public.yml
================================================
on:
push:
branches:
- main
- develop
tags:
- '*'
pull_request:
paths:
- '.github/workflows/build-public.yml'
- 'docker/prod/**'
workflow_dispatch:
permissions:
packages: write
contents: read
attestations: write
id-token: write
env:
DOCKERHUB_REPO: solidtime/solidtime
GHCR_REPO: ghcr.io/solidtime-io/solidtime
name: Build - Public
jobs:
build:
strategy:
matrix:
include:
- runs-on: "ubuntu-24.04-arm"
platform: "linux/arm64"
- runs-on: "ubuntu-24.04"
platform: "linux/amd64"
runs-on: ${{ matrix.runs-on }}
timeout-minutes: 90
steps:
- name: "Check out code"
uses: actions/checkout@v4
with:
fetch-depth: 0 # Required for WyriHaximus/github-action-get-previous-tag
- name: "Get build"
id: release-build
run: echo "build=$(git rev-parse --short=8 HEAD)" >> "$GITHUB_OUTPUT"
- name: "Get Previous tag (normal push)"
id: previoustag
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
uses: "WyriHaximus/github-action-get-previous-tag@v1"
with:
prefix: "v"
- name: "Get version"
id: release-version
run: |
if ${{ !startsWith(github.ref, 'refs/tags/v') }}; then
if ${{ startsWith(steps.previoustag.outputs.tag, 'v') }}; then
version=$(echo "${{ steps.previoustag.outputs.tag }}" | cut -c 2-)
echo "app_version=${version}" >> "$GITHUB_OUTPUT"
else
echo "ERROR: No previous tag found";
exit 1;
fi
else
version=$(echo "${{ github.ref }}" | cut -c 12-)
echo "app_version=${version}" >> "$GITHUB_OUTPUT"
fi
- name: "Copy .env template for production"
run: |
cp .env.production .env
rm .env.production .env.ci .env.example
- name: "Add version to .env"
run: sed -i 's/APP_VERSION=0.0.0/APP_VERSION=${{ steps.release-version.outputs.app_version }}/g' .env
- name: "Add build to .env"
run: sed -i 's/APP_BUILD=0/APP_BUILD=${{ steps.release-build.outputs.build }}/g' .env
- name: "Output .env"
run: cat .env
- name: "Setup PHP with PECL extension"
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: mbstring, dom, fileinfo, pgsql
- name: "Install dependencies"
run: composer install --no-dev --no-ansi --no-interaction --prefer-dist --ignore-platform-reqs --classmap-authoritative
if: steps.cache-vendor.outputs.cache-hit != 'true' # Skip if cache hit
- name: "Use Node.js"
uses: actions/setup-node@v4
with:
node-version: '20.x'
- name: "Install npm dependencies"
run: npm ci
- name: "Build"
run: npm run build
- name: "Prepare"
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: "Docker meta"
id: "meta"
uses: docker/metadata-action@v5
with:
images: |
${{ env.DOCKERHUB_REPO }}
${{ env.GHCR_REPO }}
- name: "Login to Docker Hub Container Registry"
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: "Login to GitHub Container Registry"
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: "Set up QEMU"
uses: docker/setup-qemu-action@v3
- name: "Set up Docker Buildx"
uses: docker/setup-buildx-action@v3
- name: "Build and push by digest"
id: build
uses: docker/build-push-action@v6
with:
context: .
file: docker/prod/Dockerfile
build-args: |
DOCKER_FILES_BASE_PATH=docker/prod/
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,"name=${{ env.DOCKERHUB_REPO }},${{ env.GHCR_REPO }}",push-by-digest=true,name-canonical=true,push=true
cache-from: type=gha
cache-to: type=gha,mode=max
- name: "Export digest"
run: |
mkdir -p ${{ runner.temp }}/digests
digest="${{ steps.build.outputs.digest }}"
touch "${{ runner.temp }}/digests/${digest#sha256:}"
- name: "Upload digest"
uses: actions/upload-artifact@v4
with:
name: digests-${{ env.PLATFORM_PAIR }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1
merge:
runs-on: ubuntu-latest
timeout-minutes: 90
needs:
- build
steps:
- name: "Download digests"
uses: actions/download-artifact@v4
with:
path: ${{ runner.temp }}/digests
pattern: digests-*
merge-multiple: true
- name: "Login to Docker Hub"
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: "Login to GHCR"
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: "Set up Docker Buildx"
uses: docker/setup-buildx-action@v3
- name: "Docker meta"
id: meta
uses: docker/metadata-action@v5
with:
images: |
${{ env.DOCKERHUB_REPO }}
${{ env.GHCR_REPO }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- name: "Create manifest list and push"
working-directory: ${{ runner.temp }}/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.DOCKERHUB_REPO }}@sha256:%s ' *)
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.GHCR_REPO }}@sha256:%s ' *)
- name: "Inspect image"
run: |
docker buildx imagetools inspect ${{ env.DOCKERHUB_REPO }}:${{ steps.meta.outputs.version }}
docker buildx imagetools inspect ${{ env.GHCR_REPO }}:${{ steps.meta.outputs.version }}
================================================
FILE: .github/workflows/generate-api-docs.yml
================================================
name: Generate API docs
on:
push:
branches:
- main
permissions:
contents: read
jobs:
api_docs:
runs-on: ubuntu-latest
timeout-minutes: 10
services:
pgsql_test:
image: postgres:15
env:
PGPASSWORD: 'root'
POSTGRES_DB: 'laravel'
POSTGRES_USER: 'root'
POSTGRES_PASSWORD: 'root'
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- name: "Checkout code"
uses: actions/checkout@v4
- name: "Setup PHP"
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv
- name: "Run composer install"
run: composer install -n --prefer-dist
- name: "Create build directory"
run: mkdir build
- name: Prepare Laravel Application
run: |
cp .env.ci .env
php artisan migrate
- name: "Export API docs"
run: php artisan scramble:export --path=build/api-docs.json
- name: "Upload API docs to GitHub"
uses: actions/upload-artifact@v4
with:
name: api-docs.json
path: build/api-docs.json
- name: "Download Fastfront CLI"
run: curl https://fastfront-cli.s3.fr-par.scw.cloud/fastfront-cli.phar -o fastfront-cli.phar
- name: "Deploy with Fastfront"
run: php fastfront-cli.phar deploy 9beab6cf-f459-446b-85f1-38ec007cf457 ./build
env:
FASTFRONT_API_KEY: ${{ secrets.FASTFRONT_API_DOCS_API_KEY }}
================================================
FILE: .github/workflows/npm-build.yml
================================================
name: NPM Build
on: [push]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: "Checkout code"
uses: actions/checkout@v4
- name: "Setup PHP (for Ziggy)"
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: intl, zip
coverage: none
- name: "Run composer install (for Ziggy)"
run: composer install -n --prefer-dist
- name: "Use Node.js"
uses: actions/setup-node@v4
with:
node-version: '20.x'
- name: "Install npm dependencies"
run: npm ci
- name: "Build"
run: npm run build
================================================
FILE: .github/workflows/npm-format-check.yml
================================================
name: NPM Format Check
on: [push]
jobs:
format-check:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: "Checkout code"
uses: actions/checkout@v4
- name: "Use Node.js"
uses: actions/setup-node@v4
with:
node-version: '20.x'
- name: "Install npm dependencies"
run: npm ci
- name: "Check code formatting"
run: npm run format:check
================================================
FILE: .github/workflows/npm-lint.yml
================================================
name: NPM Lint
on: [push]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: "Checkout code"
uses: actions/checkout@v4
- name: "Use Node.js"
uses: actions/setup-node@v4
with:
node-version: '20.x'
- name: "Install npm dependencies"
run: npm ci
- name: "Run linter"
run: npm run lint
================================================
FILE: .github/workflows/npm-publish-api.yml
================================================
name: Publish API package to NPM
on:
workflow_dispatch
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- name: "Checkout code"
uses: actions/checkout@v4
# Setup .npmrc file to publish to npm
- name: Install root project dependencies
run: npm ci
- uses: actions/setup-node@v4
with:
node-version: '20.x'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
run: npm ci
working-directory: ./resources/js/packages/api
- name: Build package
run: npm run build
working-directory: ./resources/js/packages/api
- name: Publish Package
run: npm publish --provenance --access public
working-directory: ./resources/js/packages/api
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
================================================
FILE: .github/workflows/npm-publish-ui.yml
================================================
name: Publish UI package to NPM
on:
workflow_dispatch
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- name: "Checkout code"
uses: actions/checkout@v4
# Setup .npmrc file to publish to npm
- uses: actions/setup-node@v4
with:
node-version: '20.x'
registry-url: 'https://registry.npmjs.org'
- name: Install root project dependencies
run: npm ci
- name: Install package dependencies
run: npm ci
working-directory: ./resources/js/packages/ui
- name: Build package
run: npm run build
working-directory: ./resources/js/packages/ui
- name: Publish Package
run: npm publish --provenance --access public
working-directory: ./resources/js/packages/ui
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
================================================
FILE: .github/workflows/npm-typecheck.yml
================================================
name: NPM Typecheck
on: [push]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: "Checkout code"
uses: actions/checkout@v4
- name: "Setup PHP (for Ziggy)"
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: intl, zip
coverage: none
- name: "Run composer install (for Ziggy)"
run: composer install -n --prefer-dist
- name: "Use Node.js"
uses: actions/setup-node@v4
with:
node-version: '20.x'
- name: "Install npm dependencies"
run: npm ci
- name: "Run type check"
run: npm run type-check
================================================
FILE: .github/workflows/phpstan.yml
================================================
name: Static code analysis (PHPStan)
on: push
permissions:
contents: read
jobs:
phpstan:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: "Checkout code"
uses: actions/checkout@v4
- name: "Setup PHP"
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv
coverage: none
- name: "Run composer install"
run: composer install -n --prefer-dist
- name: "Run PHPStan"
run: composer analyse
================================================
FILE: .github/workflows/phpunit.yml
================================================
name: PHPUnit Tests
on: push
permissions:
contents: read
jobs:
phpunit:
runs-on: ubuntu-latest
timeout-minutes: 10
strategy:
matrix:
postgres_version: [ 15, 16, 17 ]
services:
pgsql_test:
image: postgres:${{ matrix.postgres_version }}
env:
PGPASSWORD: 'root'
POSTGRES_DB: 'laravel'
POSTGRES_USER: 'root'
POSTGRES_PASSWORD: 'root'
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
gotenberg:
image: gotenberg/gotenberg:8
ports:
- 3000:3000
options: >-
--health-cmd "curl --silent --fail http://localhost:3000/health"
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- name: "Checkout code"
uses: actions/checkout@v4
- name: "Setup PHP"
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv
coverage: pcov
- name: "Run composer install"
run: composer install -n --prefer-dist
- uses: actions/setup-node@v4
with:
node-version: '20.x'
- name: "Install dependencies"
run: npm ci
- name: "Build Frontend"
run: npm run build
- name: "Prepare Laravel Application"
run: |
cp .env.ci .env
php artisan key:generate
php artisan passport:keys
- name: "Run PHPUnit"
run: php artisan test --stop-on-failure --coverage-text --coverage-clover=coverage.xml
- name: "Upload coverage reports to Codecov"
uses: codecov/codecov-action@v5.4.3
with:
token: ${{ secrets.CODECOV_TOKEN }}
slug: solidtime-io/solidtime
================================================
FILE: .github/workflows/pint.yml
================================================
name: PHP Linting
on: push
permissions:
contents: read
jobs:
pint:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: "Checkout code"
uses: actions/checkout@v4
- name: "Check code style"
uses: aglipanci/laravel-pint-action@2.5
with:
configPath: "pint.json"
================================================
FILE: .github/workflows/playwright.yml
================================================
name: Playwright Tests
on: [push]
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
shardIndex: [1, 2, 3, 4, 5, 6, 7, 8]
shardTotal: [8]
services:
mailpit:
image: 'axllent/mailpit:latest'
ports:
- 1025:1025
- 8025:8025
pgsql_test:
image: postgres:15
env:
PGPASSWORD: 'root'
POSTGRES_DB: 'laravel'
POSTGRES_USER: 'root'
POSTGRES_PASSWORD: 'root'
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- name: "Checkout code"
uses: actions/checkout@v4
- name: "Setup node"
uses: actions/setup-node@v4
with:
node-version: '20.x'
- name: "Setup PHP"
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv
coverage: none
- name: "Run composer install"
run: composer install -n --prefer-dist
- name: "Prepare Laravel Application"
run: |
cp .env.ci .env
php artisan key:generate
php artisan passport:keys
php artisan migrate --seed
- name: "Install dependencies"
run: npm ci
- name: "Build Frontend"
run: npm run build
- name: "Install FrankenPHP"
run: |
ARCH="$(uname -m)"
curl -fsSL "https://github.com/dunglas/frankenphp/releases/latest/download/frankenphp-linux-${ARCH}" -o /usr/local/bin/frankenphp
chmod +x /usr/local/bin/frankenphp
- name: "Run Laravel Octane Server"
run: php artisan octane:start --server=frankenphp --host=127.0.0.1 --port=8000 --workers=4 --max-requests=500 > /dev/null 2>&1 &
env:
OCTANE_SERVER: frankenphp
- name: "Install Playwright Browsers"
run: npx playwright install --with-deps
- name: "Run Playwright tests"
run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
env:
PLAYWRIGHT_BASE_URL: 'http://127.0.0.1:8000'
MAILPIT_BASE_URL: 'http://localhost:8025'
- name: "Upload blob report"
uses: actions/upload-artifact@v4
if: always()
with:
name: blob-report-${{ matrix.shardIndex }}
path: blob-report/
retention-days: 7
merge-reports:
if: always()
needs: [test]
runs-on: ubuntu-latest
steps:
- name: "Checkout code"
uses: actions/checkout@v4
- name: "Setup node"
uses: actions/setup-node@v4
with:
node-version: '20.x'
- name: "Install dependencies"
run: npm ci
- name: "Download blob reports"
uses: actions/download-artifact@v4
with:
path: all-blob-reports
pattern: blob-report-*
merge-multiple: true
- name: "Merge reports"
run: npx playwright merge-reports --reporter html ./all-blob-reports
- name: "Upload merged HTML report"
uses: actions/upload-artifact@v4
with:
name: playwright-report
path: playwright-report/
retention-days: 30
================================================
FILE: .gitignore
================================================
/.phpunit.cache
node_modules
dist
/public/build
/public/hot
/public/storage
/public/css
/public/js
/public/vendor
/lang/vendor
/storage/*.key
/vendor
.env
.env.backup
.phpunit.result.cache
Homestead.json
Homestead.yaml
auth.json
npm-debug.log
yarn-error.log
/.fleet
/.idea
/.vscode
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
/coverage
/extensions
!/extensions/.gitkeep
!/extensions/extensions_autoload.php
/auth.json
/modules_statuses.json
/k8s
/_ide_helper.php
/.phpstorm.meta.php
/.rnd
/caddy
/frankenphp
/public/frankenphp-worker.php
/data
/config/caddy
/config/composer
================================================
FILE: .prettierignore
================================================
# Ignore build outputs
node_modules/
vendor/
storage/
bootstrap/cache/
public/build/
public/hot/
# Ignore lock files
package-lock.json
composer.lock
# Ignore generated files
*.min.js
*.min.css
# Ignore test results
test-results/
playwright-report/
# Ignore IDE files
.idea/
.vscode/
# Ignore OS files
.DS_Store
Thumbs.db
================================================
FILE: .prettierrc.json
================================================
{
"trailingComma": "es5",
"tabWidth": 4,
"singleQuote": true,
"bracketSameLine": true,
"quoteProps": "preserve",
"printWidth": 100
}
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Code of Conduct
The goal is to create a community that is open and welcoming to all individuals.
To achieve this, we have developed a code of conduct that outlines the expectations for behavior of all members of our community.
## Pledge
This community is founded on respect and understanding.
All members are expected to treat others with respect and empathy, and to not tolerate any form of discrimination,
harassment, or attacks.
## Expectations
Examples of behavior that contributes to creating a positive environment include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery and sexual attention or advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting
## Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate
and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits,
issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily
or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Contact
If you feel uncomfortable or believe that someone has violated the code of conduct, please contact us at [hello@solidtime.io](mailto:hello@solidtime.io).
We will thoroughly investigate the incident and aim for the best possible outcome.
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to solidtime
Contributions are greatly apprecited, please make sure to read the rules and vision for solidtime before contributing.
## Rules
### Issues for Bugs, Discussions for Feature requests
In order to keep the issues of the repository clean we decided to only use them for bugs. Feature Requests and enhancement are handled in discussions. This also helps us to see which feature requests are popular as they can be upvoted.
### Only work on approved issues
To respect your time and help us manage contributions effectively, please open an issue or start a discussion and wait for approval before submitting a pull request (PR). This does not apply to tiny fixes or changes however, please keep in mind that we might not merge PRs for various reasons.
### Contributor License Agreement
You'll also notice that we’ve set up a [Contributor License Agreement (CLA)](https://cla-assistant.io/solidtime-io/solidtime), which must be signed before any PR can be merged. Don’t worry - the process is quick and only takes a few clicks.
We want to be transparent about why we require the CLA and what it means for your contributions and the codebase. That’s why we’ve written a few paragraphs below outlining our plans and vision for solidtime in the **Vision** part of this document.
### Prevent Duplicate Work
Before you submit a new PR, make sure that none exists already. If you plan to work on an issue, make sure to let us and others know by commenting on the issue/discussion.
### Give context
Tell us what you thinking was behind the decisions you made while drafting the PR. Treat the PR itself as documentation for everyone who wants to go back and understand why certain decisions were made.
### Summarize your PR
Please make sure to include a short summary at the top of your PR to make it easy for us to quickly check what the PR is about, without looking at the code changes.
### Use Github Keywords and Auto-Link Issues
Use phrases like "Closes #123" or "Fixes #123" in the PR description to link the PR with the issue that you are adressing.
### Mention what you tested and how
Explain how you tested and validated the implementation.
### Keep Naming consistent
Look at existing code patterns and use naming conventions that already exist in the code base.
### Testing
We have an exhaustive test-suite of PHPUnit (Backend) and Playwright (Frontend) testing. Whereever applicable please make sure to write add tests to the codebase.
### Linting & Formatting
Make sure to run linting and formatting commands before you commit the changes.
For backend changes:
```
composer fix
composer analyse
```
For frontend changes:
```
npm run lint:fix
npm run format
```
## Vision
We started solidtime to provide an open infrastructure solution for time tracking—one that empowers teams and individuals to fully own their data, instead of depending on proprietary platforms. We believe infrastructure software should be open, accessible, and built to last. However, competing with established market leaders in this space requires long-term financial sustainability.
solidtime is licensed under the AGPL, which we believe is the best available license to strike a balance between openness and financial viability. The AGPL gives us, as the copyright holders, certain exclusive rights that we plan to leverage to fund development. To ensure we retain those rights across the entire codebase, we've put a CLA in place that contributors must sign before submitting code.
One of solidtime’s key advantages is that it's built to be self-hostable. This makes it a great solution for organizations like governments, healthcare providers, and enterprises that are required to keep data on their own infrastructure due to regulations or internal policies. These organizations may need custom licenses, integrations, or modifications that aren't suitable for the open-source version. To support them, we offer relicensed versions of solidtime along with support plans.
We’ll also provide proprietary extensions for solidtime. These will be available to enterprise customers with support plans, but also to individual users or teams who don’t need support, at much more accessible price points. For companies running solidtime on their own infrastructure, this is the easiest way to support the project while gaining additional functionality. While we plan to make it easier to build custom extensions in the future, our current APIs are still highly experimental.
Finally - and perhaps most importantly - we offer a hosted SaaS version called solidtime Cloud, for users who can’t or don’t want to run the software themselves. This version includes proprietary extensions, always runs the latest commit, and includes monitoring and billing features available exclusively on this hosted instance. We expect solidtime Cloud to play a critical role in funding the project long-term.
Having full control over the source code’s licensing also gives us the ability to change the license of the main project in the future. That said, we have no plans to do so and would only consider it in extreme cases - for example, if a malicious actor were to directly compete with our hosted service in a way that threatens the sustainability of the project, the legal interpretation of AGPL changes in a way that would make it unreasonable to use for certain companies, or a new similar license gains wide-spread adoption. Regardless, solidtime will always remain free to self-host for individuals and companies who use it as part of their work, and all previous releases will remain licensed under AGPL.
If you are using the open-source version of solidtime and want to support us, the best way to do so is to spread the word.
================================================
FILE: LICENSE.md
================================================
GNU Affero General Public License
=================================
_Version 3, 19 November 2007_
_Copyright © 2007 Free Software Foundation, Inc. <<http://fsf.org/>>_
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
## Preamble
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights
with two steps: **(1)** assert copyright on the software, and **(2)** offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
The precise terms and conditions for copying, distribution and
modification follow.
## TERMS AND CONDITIONS
### 0. Definitions
“This License” refers to version 3 of the GNU Affero General Public License.
“Copyright” also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
“The Program” refers to any copyrightable work licensed under this
License. Each licensee is addressed as “you”. “Licensees” and
“recipients” may be individuals or organizations.
To “modify” a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a “modified version” of the
earlier work or a work “based on” the earlier work.
A “covered work” means either the unmodified Program or a work based
on the Program.
To “propagate” a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To “convey” a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays “Appropriate Legal Notices”
to the extent that it includes a convenient and prominently visible
feature that **(1)** displays an appropriate copyright notice, and **(2)**
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
### 1. Source Code
The “source code” for a work means the preferred form of the work
for making modifications to it. “Object code” means any non-source
form of a work.
A “Standard Interface” means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The “System Libraries” of an executable work include anything, other
than the work as a whole, that **(a)** is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and **(b)** serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
“Major Component”, in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The “Corresponding Source” for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
### 2. Basic Permissions
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
### 3. Protecting Users' Legal Rights From Anti-Circumvention Law
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
### 4. Conveying Verbatim Copies
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
### 5. Conveying Modified Source Versions
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
* **a)** The work must carry prominent notices stating that you modified
it, and giving a relevant date.
* **b)** The work must carry prominent notices stating that it is
released under this License and any conditions added under section 7.
This requirement modifies the requirement in section 4 to
“keep intact all notices”.
* **c)** You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
* **d)** If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
“aggregate” if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
### 6. Conveying Non-Source Forms
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
* **a)** Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
* **b)** Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either **(1)** a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or **(2)** access to copy the
Corresponding Source from a network server at no charge.
* **c)** Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
* **d)** Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
* **e)** Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A “User Product” is either **(1)** a “consumer product”, which means any
tangible personal property which is normally used for personal, family,
or household purposes, or **(2)** anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, “normally used” refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
“Installation Information” for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
### 7. Additional Terms
“Additional permissions” are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
* **a)** Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
* **b)** Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
* **c)** Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
* **d)** Limiting the use for publicity purposes of names of licensors or
authors of the material; or
* **e)** Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
* **f)** Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered “further
restrictions” within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
### 8. Termination
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated **(a)**
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and **(b)** permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
### 9. Acceptance Not Required for Having Copies
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
### 10. Automatic Licensing of Downstream Recipients
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An “entity transaction” is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
### 11. Patents
A “contributor” is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's “contributor version”.
A contributor's “essential patent claims” are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, “control” includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a “patent license” is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To “grant” such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either **(1)** cause the Corresponding Source to be so
available, or **(2)** arrange to deprive yourself of the benefit of the
patent license for this particular work, or **(3)** arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. “Knowingly relying” means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is “discriminatory” if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license **(a)** in connection with copies of the covered work
conveyed by you (or copies made from those copies), or **(b)** primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
### 12. No Surrender of Others' Freedom
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
### 13. Remote Network Interaction; Use with the GNU General Public License
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
### 14. Revised Versions of this License
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Public License “or any later version” applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
### 15. Disclaimer of Warranty
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
### 16. Limitation of Liability
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
### 17. Interpretation of Sections 15 and 16
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
_END OF TERMS AND CONDITIONS_
## How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the “copyright” line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 2024 Gregor Vostrak & Constantin Graf
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a “Source” link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a “copyright disclaimer” for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<<http://www.gnu.org/licenses/>>.
================================================
FILE: README.md
================================================
# solidtime - The modern Open-Source Time Tracker
[](https://github.com/solidtime-io/solidtime/blob/main/LICENSE.md)
[](https://codecov.io/gh/solidtime-io/solidtime)



solidtime is a modern open-source time tracking application for Freelancers and Agencies.
## Features
- Time tracking: Track your time with a modern and easy-to-use interface
- Projects: Create and manage projects and assign project members
- Tasks: Create and manage tasks and assign tasks to projects
- Clients: Create and manage clients and assign clients to projects
- Billable rates: Set billable rates for projects, project members, organization members and organizations
- Multiple organizations: Create and manage multiple organizations with one account
- Roles and permissions: Create and manage organizations
- Import: Import your time tracking data from other time tracking applications (Supported: Toggl, Clockify, Timeentry CSV)
## Self Hosting
If you are looking into self-hosting solidtime, you can find the guides [here](https://docs.solidtime.io/self-hosting/intro)
We also have an examples repository [here](https://github.com/solidtime-io/self-hosting-examples)
If you do not want to self-host solidtime or try it out you can sign up for [solidtime cloud](https://www.solidtime.io/)
## Issues & Feature Requests
If you find any **bugs in solidtime**, please feel free to [**open an issue**](https://github.com/solidtime-io/solidtime/issues/new) in this repository, with instructions on how to reproduce the bug.
If you have a **feature request**, please [**create a discussion**](https://github.com/solidtime-io/solidtime/discussions/new?category=feature-requests) in this repository.
## Contributing
Please open an issue or start a discussion and wait for approval before submitting a pull request. This does not apply to tiny fixes or changes however, please keep in mind that we might not merge PRs for various reasons.
**If you submit an AI slop pull request (especially without following the proper procedure), you will be banned from future contributions to solidtime.**
Please read the [CONTRIBUTING.md](./CONTRIBUTING.md) before sumbitting a Pull Request.
We do accept contributions in the [documentation repository](https://github.com/solidtime-io/docs) f.e. to add new self-hosting guides.
## Security
Looking to report a vulnerability? Please refer our [SECURITY.md](./SECURITY.md) file.
## License
This project is open-source and available under the GNU Affero General Public License v3.0 (AGPL v3). Please see the [license file](LICENSE.md) for more information.
================================================
FILE: SECURITY.md
================================================
# Security Policy
## Reporting a Vulnerability
If you discover a security vulnerability regarding this project, please e-mail me to [security@solidtime.io](mailto:security@solidtime.io)!
================================================
FILE: app/Actions/Fortify/CreateNewUser.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Fortify;
use App\Enums\Weekday;
use App\Events\NewsletterRegistered;
use App\Models\User;
use App\Service\IpLookup\IpLookupServiceContract;
use App\Service\TimezoneService;
use App\Service\UserService;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
use Korridor\LaravelModelValidationRules\Rules\UniqueEloquent;
use Laravel\Fortify\Contracts\CreatesNewUsers;
use Laravel\Jetstream\Jetstream;
use Log;
class CreateNewUser implements CreatesNewUsers
{
use PasswordValidationRules;
/**
* Create a newly registered user.
*
* @param array<string, mixed> $input
*
* @throws ValidationException
*/
public function create(array $input): User
{
if (! config('app.enable_registration')) {
throw ValidationException::withMessages([
'email' => [__('Registration is disabled.')],
]);
}
Validator::make($input, [
'name' => [
'required',
'string',
'max:255',
],
'email' => [
'required',
'string',
'email:rfc,strict',
'max:255',
UniqueEloquent::make(User::class, 'email', function (Builder $builder): Builder {
/** @var Builder<User> $builder */
return $builder->where('is_placeholder', '=', false);
}),
],
'password' => $this->passwordRules(),
'terms' => Jetstream::hasTermsAndPrivacyPolicyFeature() ? ['accepted', 'required'] : '',
'newsletter_consent' => [
'boolean',
],
])->validate();
$timezone = null;
if (array_key_exists('timezone', $input) && is_string($input['timezone'])) {
if (app(TimezoneService::class)->isValid($input['timezone'])) {
$timezone = $input['timezone'];
} else {
$timezone = app(TimezoneService::class)->mapLegacyTimezone($input['timezone']);
if ($timezone === null) {
Log::debug('Invalid timezone', ['timezone' => $input['timezone']]);
}
}
}
$ipLookupResponse = app(IpLookupServiceContract::class)->lookup(request()->ip());
$startOfWeek = Weekday::Monday;
$numberFormat = null;
$currencyFormat = null;
$dateFormat = null;
$intervalFormat = null;
$timeFormat = null;
$currency = null;
if ($ipLookupResponse !== null) {
$startOfWeek = $ipLookupResponse->startOfWeek ?? Weekday::Monday;
if ($timezone === null) {
$timezone = $ipLookupResponse->timezone;
}
$currency = $ipLookupResponse->currency;
}
$user = null;
DB::transaction(function () use (&$user, $input, $timezone, $startOfWeek, $currency, $numberFormat, $currencyFormat, $dateFormat, $intervalFormat, $timeFormat): void {
$userService = app(UserService::class);
$user = $userService->createUser(
$input['name'],
$input['email'],
$input['password'],
$timezone ?? 'UTC',
$startOfWeek,
$currency,
$numberFormat,
$currencyFormat,
$dateFormat,
$intervalFormat,
$timeFormat
);
});
$newsletterConsent = isset($input['newsletter_consent']) && (bool) $input['newsletter_consent'];
if ($newsletterConsent) {
NewsletterRegistered::dispatch($input['name'], $input['email'], $user->getKey());
}
return $user;
}
}
================================================
FILE: app/Actions/Fortify/PasswordValidationRules.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Fortify;
use Illuminate\Contracts\Validation\Rule;
use Illuminate\Validation\Rules\Password;
trait PasswordValidationRules
{
/**
* Get the validation rules used to validate passwords.
*
* @return array<int, Rule|string>
*/
protected function passwordRules(): array
{
return ['required', 'string', Password::default(), 'confirmed'];
}
}
================================================
FILE: app/Actions/Fortify/ResetUserPassword.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Fortify;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Laravel\Fortify\Contracts\ResetsUserPasswords;
class ResetUserPassword implements ResetsUserPasswords
{
use PasswordValidationRules;
/**
* Validate and reset the user's forgotten password.
*
* @param array<string, string> $input
*/
public function reset(User $user, array $input): void
{
Validator::make($input, [
'password' => $this->passwordRules(),
])->validate();
$user->forceFill([
'password' => Hash::make($input['password']),
])->save();
}
}
================================================
FILE: app/Actions/Fortify/UpdateUserPassword.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Fortify;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Laravel\Fortify\Contracts\UpdatesUserPasswords;
class UpdateUserPassword implements UpdatesUserPasswords
{
use PasswordValidationRules;
/**
* Validate and update the user's password.
*
* @param array<string, string> $input
*/
public function update(User $user, array $input): void
{
Validator::make($input, [
'current_password' => ['required', 'string', 'current_password:web'],
'password' => $this->passwordRules(),
], [
'current_password.current_password' => __('The provided password does not match your current password.'),
])->validateWithBag('updatePassword');
$user->forceFill([
'password' => Hash::make($input['password']),
])->save();
}
}
================================================
FILE: app/Actions/Fortify/UpdateUserProfileInformation.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Fortify;
use App\Enums\Weekday;
use App\Models\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Illuminate\Validation\ValidationException;
use Korridor\LaravelModelValidationRules\Rules\UniqueEloquent;
use Laravel\Fortify\Contracts\UpdatesUserProfileInformation;
class UpdateUserProfileInformation implements UpdatesUserProfileInformation
{
/**
* Validate and update the given user's profile information.
*
* @param array<string, mixed> $input
*
* @throws ValidationException
*/
public function update(User $user, array $input): void
{
Validator::make($input, [
'name' => [
'required',
'string',
'max:255',
],
'email' => [
'required',
'email',
'max:255',
UniqueEloquent::make(User::class, 'email')->ignore($user->id)->query(function (Builder $query) {
/** @var Builder<User> $query */
return $query->where('is_placeholder', '=', false);
}),
],
'photo' => [
'nullable',
'mimes:jpg,jpeg,png',
'max:1024',
],
'timezone' => [
'required',
'timezone:all',
],
'week_start' => [
'required',
Rule::enum(Weekday::class),
],
])->validateWithBag('updateProfileInformation');
if (isset($input['photo'])) {
$user->updateProfilePhoto($input['photo']);
}
if ($input['email'] !== $user->email) {
$user->forceFill([
'name' => $input['name'],
'email' => $input['email'],
'email_verified_at' => null,
'timezone' => $input['timezone'],
'week_start' => $input['week_start'],
])->save();
$user->sendEmailVerificationNotification();
} else {
$user->forceFill([
'name' => $input['name'],
'timezone' => $input['timezone'],
'week_start' => $input['week_start'],
])->save();
}
}
}
================================================
FILE: app/Actions/Jetstream/AddOrganizationMember.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Jetstream;
use App\Enums\Role;
use App\Models\Organization;
use App\Models\User;
use App\Service\MemberService;
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\In;
use Korridor\LaravelModelValidationRules\Rules\ExistsEloquent;
use Laravel\Jetstream\Contracts\AddsTeamMembers;
class AddOrganizationMember implements AddsTeamMembers
{
/**
* Add a new team member to the given team.
*/
public function add(User $owner, Organization $organization, string $email, ?string $role = null): void
{
Gate::forUser($owner)->authorize('addTeamMember', $organization); // TODO: refactor after owner refactoring
$this->validate($organization, $email, $role);
$newOrganizationMember = User::query()
->where('email', $email)
->where('is_placeholder', '=', false)
->firstOrFail();
app(MemberService::class)->addMember($newOrganizationMember, $organization, Role::from($role));
}
/**
* Validate the add member operation.
*/
protected function validate(Organization $organization, string $email, ?string $role): void
{
Validator::make([
'email' => $email,
'role' => $role,
], $this->rules())->after(
$this->ensureUserIsNotAlreadyOnTeam($organization, $email)
)->validateWithBag('addTeamMember');
}
/**
* Get the validation rules for adding a team member.
*
* @return array<string, array<ValidationRule|Rule|string|In>>
*/
protected function rules(): array
{
return [
'email' => [
'required',
'email',
ExistsEloquent::make(User::class, 'email', function (Builder $builder) {
/** @var Builder<User> $builder */
return $builder->where('is_placeholder', '=', false);
})->withMessage(__('We were unable to find a registered user with this email address.')),
],
'role' => [
'required',
'string',
Rule::in([
Role::Admin->value,
Role::Manager->value,
Role::Employee->value,
]),
],
];
}
/**
* Ensure that the user is not already on the team.
*/
protected function ensureUserIsNotAlreadyOnTeam(Organization $team, string $email): Closure
{
return function ($validator) use ($team, $email): void {
$validator->errors()->addIf(
$team->hasRealUserWithEmail($email),
'email',
__('This user already belongs to the team.')
);
};
}
}
================================================
FILE: app/Actions/Jetstream/CreateOrganization.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Jetstream;
use App\Events\AfterCreateOrganization;
use App\Models\Organization;
use App\Models\User;
use App\Service\IpLookup\IpLookupServiceContract;
use App\Service\OrganizationService;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
use Laravel\Jetstream\Contracts\CreatesTeams;
use Laravel\Jetstream\Jetstream;
class CreateOrganization implements CreatesTeams
{
/**
* Validate and create a new team for the given user.
*
* @param array<string, string> $input
*
* @throws AuthorizationException
* @throws ValidationException
*/
public function create(User $user, array $input): Organization
{
Gate::forUser($user)->authorize('create', Jetstream::newTeamModel());
Validator::make($input, [
'name' => ['required', 'string', 'max:255'],
])->validateWithBag('createTeam');
$ipLookupResponse = app(IpLookupServiceContract::class)->lookup(request()->ip());
$currency = null;
if ($ipLookupResponse !== null) {
$currency = $ipLookupResponse->currency;
}
$organization = app(OrganizationService::class)->createOrganization(
$input['name'],
$user,
false,
$currency
);
$user->switchTeam($organization);
// Note: The refresh is necessary for currently unknown reasons. Do not remove it.
$organization = $organization->refresh();
AfterCreateOrganization::dispatch($organization);
return $organization;
}
}
================================================
FILE: app/Actions/Jetstream/DeleteOrganization.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Jetstream;
use App\Models\Organization;
use App\Service\DeletionService;
use Laravel\Jetstream\Contracts\DeletesTeams;
class DeleteOrganization implements DeletesTeams
{
/**
* Delete the given team.
*/
public function delete(Organization $organization): void
{
/** @see ValidateOrganizationDeletion */
app(DeletionService::class)->deleteOrganization($organization);
}
}
================================================
FILE: app/Actions/Jetstream/DeleteUser.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Jetstream;
use App\Exceptions\Api\ApiException;
use App\Models\User;
use App\Service\DeletionService;
use Illuminate\Validation\ValidationException;
use Laravel\Jetstream\Contracts\DeletesUsers;
class DeleteUser implements DeletesUsers
{
/**
* Delete the given user.
*
* @throws ValidationException
*/
public function delete(User $user): void
{
try {
app(DeletionService::class)->deleteUser($user);
} catch (ApiException $exception) {
throw ValidationException::withMessages([
'password' => $exception->getTranslatedMessage(),
]);
}
}
}
================================================
FILE: app/Actions/Jetstream/InviteOrganizationMember.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Jetstream;
use App\Exceptions\MovedToApiException;
use App\Models\Organization;
use App\Models\User;
use Exception;
use Laravel\Jetstream\Contracts\InvitesTeamMembers;
class InviteOrganizationMember implements InvitesTeamMembers
{
/**
* Invite a new team member to the given team.
*
* @throws Exception
*/
public function invite(User $user, Organization $organization, string $email, ?string $role = null): void
{
throw new MovedToApiException;
}
}
================================================
FILE: app/Actions/Jetstream/RemoveOrganizationMember.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Jetstream;
use App\Exceptions\MovedToApiException;
use App\Models\Organization;
use App\Models\User;
use Exception;
use Laravel\Jetstream\Contracts\RemovesTeamMembers;
class RemoveOrganizationMember implements RemovesTeamMembers
{
/**
* Remove the team member from the given team.
*
* @throws Exception
*/
public function remove(User $user, Organization $organization, User $teamMember): void
{
throw new MovedToApiException;
}
}
================================================
FILE: app/Actions/Jetstream/UpdateMemberRole.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Jetstream;
use App\Enums\Role;
use App\Exceptions\MovedToApiException;
use App\Models\Member;
use App\Models\Organization;
use App\Models\User;
use Exception;
class UpdateMemberRole
{
/**
* Update the role for the given team member.
*
* @throws Exception
*/
public function update(User $actingUser, Organization $organization, string $userId, string $role): void
{
throw new MovedToApiException;
}
}
================================================
FILE: app/Actions/Jetstream/UpdateOrganization.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Jetstream;
use App\Models\Organization;
use App\Models\User;
use App\Rules\CurrencyRule;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
use Laravel\Jetstream\Contracts\UpdatesTeamNames;
class UpdateOrganization implements UpdatesTeamNames
{
/**
* Validate and update the given team's name.
*
* @param array<string, string> $input
*
* @throws AuthorizationException
* @throws ValidationException
*/
public function update(User $user, Organization $organization, array $input): void
{
Gate::forUser($user)->authorize('update', $organization);
Validator::make($input, [
'name' => [
'required',
'string',
'max:255',
],
'currency' => [
'required',
'string',
new CurrencyRule,
],
])->validateWithBag('updateTeamName');
$organization->forceFill([
'name' => $input['name'],
'currency' => $input['currency'],
])->save();
}
}
================================================
FILE: app/Actions/Jetstream/ValidateOrganizationDeletion.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Jetstream;
use App\Models\Organization;
use App\Models\User;
use App\Service\PermissionStore;
use Illuminate\Auth\Access\AuthorizationException;
class ValidateOrganizationDeletion
{
/**
* Validate that the team can be deleted by the given user.
*
* @param User $user Authenticated user
* @param Organization $organization Organization to be deleted
*
* @throws AuthorizationException
*/
public function validate(User $user, Organization $organization): void
{
if (! app(PermissionStore::class)->userHas($organization, $user, 'organizations:delete')) {
throw new AuthorizationException;
}
}
}
================================================
FILE: app/Console/Commands/Admin/OrganizationDeleteCommand.php
================================================
<?php
declare(strict_types=1);
namespace App\Console\Commands\Admin;
use App\Models\Organization;
use App\Service\DeletionService;
use Illuminate\Console\Command;
use Illuminate\Support\Str;
class OrganizationDeleteCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'admin:organization:delete
{ organization : The ID of the organization to delete }';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Delete a organization';
/**
* Execute the console command.
*/
public function handle(DeletionService $deletionService): int
{
$organizationId = $this->argument('organization');
if (! Str::isUuid($organizationId)) {
$this->error('Organization ID must be a valid UUID.');
return self::FAILURE;
}
/** @var Organization|null $organization */
$organization = Organization::find($organizationId);
if ($organization === null) {
$this->error('Organization with ID '.$organizationId.' not found.');
return self::FAILURE;
}
$this->info('Deleting organization with ID '.$organization->getKey());
$deletionService->deleteOrganization($organization);
$this->info('Organization with ID '.$organization->getKey().' has been deleted.');
return self::SUCCESS;
}
}
================================================
FILE: app/Console/Commands/Admin/UserCreateCommand.php
================================================
<?php
declare(strict_types=1);
namespace App\Console\Commands\Admin;
use App\Enums\Weekday;
use App\Models\Organization;
use App\Models\User;
use App\Service\UserService;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use LogicException;
class UserCreateCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'admin:user:create
{ name : The name of the user }
{ email : The email of the user }
{ --ask-for-password : Ask for the password, otherwise the command will generate a random one }
{ --verify-email : Verify the email address of the user }';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new user';
/**
* Execute the console command.
*/
public function handle(): int
{
$name = $this->argument('name');
$email = $this->argument('email');
$askForPassword = (bool) $this->option('ask-for-password');
$verifyEmail = (bool) $this->option('verify-email');
if (User::query()->where('email', $email)->where('is_placeholder', '=', false)->exists()) {
$this->error('User with email "'.$email.'" already exists.');
return self::FAILURE;
}
if ($askForPassword) {
$outputPassword = false;
$password = $this->secret('Enter the password');
} else {
$outputPassword = true;
$password = bin2hex(random_bytes(16));
}
$user = null;
DB::transaction(function () use (&$user, $name, $email, $password, $verifyEmail): void {
$user = app(UserService::class)->createUser(
$name,
$email,
$password,
'UTC',
Weekday::Monday,
null,
verifyEmail: $verifyEmail
);
});
/** @var Organization|null $organization */
$organization = $user->ownedTeams->first();
if ($organization === null) {
throw new LogicException('User does not have an organization');
}
$this->info('Created user "'.$name.'" ("'.$email.'")');
$this->line('ID: '.$user->getKey());
$this->line('Name: '.$name);
$this->line('Email: '.$email);
if ($outputPassword) {
$this->line('Password: '.$password);
}
$this->line('Timezone: '.$user->timezone);
$this->line('Week start: '.$user->week_start->value);
// Organization
$this->line('Currency: '.$organization->currency);
return self::SUCCESS;
}
}
================================================
FILE: app/Console/Commands/Admin/UserVerifyCommand.php
================================================
<?php
declare(strict_types=1);
namespace App\Console\Commands\Admin;
use App\Models\User;
use Illuminate\Auth\Events\Verified;
use Illuminate\Console\Command;
class UserVerifyCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'admin:user:verify
{ email : The email of the user to verify }';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Verify the email address of an user';
/**
* Execute the console command.
*/
public function handle(): int
{
$email = $this->argument('email');
$this->info('Start verifying user with email "'.$email.'"');
/** @var User|null $user */
$user = User::query()->where('email', $email)
->where('is_placeholder', '=', false)
->first();
if ($user === null) {
$this->error('User with email "'.$email.'" not found.');
return self::FAILURE;
}
if ($user->hasVerifiedEmail()) {
$this->info('User with email "'.$email.'" already verified.');
return self::FAILURE;
}
$user->markEmailAsVerified();
event(new Verified($user));
$this->info('User with email "'.$email.'" has been verified.');
return self::SUCCESS;
}
}
================================================
FILE: app/Console/Commands/Auth/AuthSendReminderForExpiringApiTokensCommand.php
================================================
<?php
declare(strict_types=1);
namespace App\Console\Commands\Auth;
use App\Mail\AuthApiTokenExpirationReminderMail;
use App\Mail\AuthApiTokenExpiredMail;
use App\Models\Passport\Token;
use App\Models\User;
use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Mail;
class AuthSendReminderForExpiringApiTokensCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'auth:send-mails-expiring-api-tokens '.
' { --dry-run : Do not actually send emails or save anything to the database, just output what would happen }';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Sends emails about expiring API tokens, one week before and when they expired.';
/**
* Execute the console command.
*/
public function handle(): int
{
$dryRun = (bool) $this->option('dry-run');
if ($dryRun) {
$this->comment('Running in dry-run mode. No emails will be sent and nothing will be saved to the database.');
}
$this->comment('Sending reminder emails about expiring API tokens...');
$sentMails = 0;
Token::query()
->where('expires_at', '<=', Carbon::now()->addDays(7))
->whereNull('reminder_sent_at')
->with([
'client',
'user',
])
->whereHas('user', function (Builder $query): void {
/** @var Builder<User> $query */
$query->where('is_placeholder', '=', false);
})
->isApiToken(true)
->orderBy('created_at', 'asc')
->chunk(500, function (Collection $tokens) use ($dryRun, &$sentMails): void {
/** @var Collection<int, Token> $tokens */
foreach ($tokens as $token) {
$user = $token->user;
$this->info('Start sending email to user "'.$user->email.'" ('.$user->getKey().') reminding about API token '.$token->getKey());
$sentMails++;
if (! $dryRun) {
Mail::to($user->email)
->queue(new AuthApiTokenExpirationReminderMail($token, $user));
$token->reminder_sent_at = Carbon::now();
$token->save();
}
}
});
$this->comment('Finished sending '.$sentMails.' expiring API token emails...');
$this->comment('Sent emails about expired API tokens');
$sentMails = 0;
Token::query()
->where('expires_at', '<=', Carbon::now())
->whereNull('expired_info_sent_at')
->with([
'client',
'user',
])
->whereHas('user', function (Builder $query): void {
/** @var Builder<User> $query */
$query->where('is_placeholder', '=', false);
})
->isApiToken(true)
->orderBy('created_at', 'asc')
->chunk(500, function (Collection $tokens) use ($dryRun, &$sentMails): void {
/** @var Collection<int, Token> $tokens */
foreach ($tokens as $token) {
$user = $token->user;
$this->info('Start sending email to user "'.$user->email.'" ('.$user->getKey().') about expired API token '.$token->getKey());
$sentMails++;
if (! $dryRun) {
Mail::to($user->email)
->queue(new AuthApiTokenExpiredMail($token, $user));
$token->expired_info_sent_at = Carbon::now();
$token->save();
}
}
});
$this->comment('Finished sending '.$sentMails.' expired API token emails...');
return self::SUCCESS;
}
}
================================================
FILE: app/Console/Commands/Correction/CorrectionPlaceholderMembersCommand.php
================================================
<?php
declare(strict_types=1);
namespace App\Console\Commands\Correction;
use App\Enums\Role;
use App\Models\Member;
use App\Models\User;
use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\Builder;
class CorrectionPlaceholderMembersCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'correction:placeholder-members '.
' { --dry-run : Do not actually save anything to the database, just output what would happen }';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Sets all members who belong to a placeholder user to role placeholder';
/**
* Execute the console command.
*/
public function handle(): int
{
$this->comment('Sets all members who belong to a placeholder user to role placeholder...');
$dryRun = (bool) $this->option('dry-run');
if ($dryRun) {
$this->comment('Running in dry-run mode. Nothing will be saved to the database.');
}
$members = Member::query()
->where('role', '!=', Role::Placeholder->value)
->whereHas('user', function (Builder $builder): void {
/** @var Builder<User> $builder */
$builder->where('is_placeholder', '=', true);
})
->get();
foreach ($members as $member) {
/** @var Member $member */
$member->role = Role::Placeholder->value;
if (! $dryRun) {
$member->save();
}
$this->line('Set role of member (id='.$member->getKey().') to placeholder');
}
return self::SUCCESS;
}
}
================================================
FILE: app/Console/Commands/Report/ReportSetExpiredToPrivateCommand.php
================================================
<?php
declare(strict_types=1);
namespace App\Console\Commands\Report;
use App\Models\Report;
use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Carbon;
use LogicException;
class ReportSetExpiredToPrivateCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'report:set-expired-to-private '.
' { --dry-run : Do not actually save anything to the database, just output what would happen }';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Makes public reports private if the public_until date has passed.';
/**
* Execute the console command.
*/
public function handle(): int
{
$this->comment('Makes public reports private if the public_until date has passed...');
$dryRun = (bool) $this->option('dry-run');
if ($dryRun) {
$this->comment('Running in dry-run mode. Nothing will be saved to the database.');
}
$resetReports = 0;
Report::query()
->where('public_until', '<', Carbon::now())
->orderBy('created_at', 'asc')
->chunk(500, function (Collection $reports) use ($dryRun, &$resetReports): void {
/** @var Collection<int, Report> $reports */
foreach ($reports as $report) {
$publicUntil = $report->public_until;
if ($publicUntil === null) {
throw new LogicException('public_until should not be null');
}
$this->info('Make report "'.$report->name.'" ('.$report->getKey().') private, expired: '.
$publicUntil->toIso8601ZuluString().' ('.$publicUntil->diffForHumans().')');
$resetReports++;
if (! $dryRun) {
$report->is_public = false;
$report->share_secret = null;
$report->save();
}
}
});
$this->comment('Finished setting '.$resetReports.' expired reports to private...');
return self::SUCCESS;
}
}
================================================
FILE: app/Console/Commands/SelfHost/SelfHostCheckForUpdateCommand.php
================================================
<?php
declare(strict_types=1);
namespace App\Console\Commands\SelfHost;
use App\Service\ApiService;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Cache;
class SelfHostCheckForUpdateCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'self-host:check-for-update';
/**
* The console command description.
*
* @var string
*/
protected $description = '';
/**
* Execute the console command.
*/
public function handle(): int
{
$apiService = app(ApiService::class);
$latestVersion = $apiService->checkForUpdate();
if ($latestVersion === null) {
$this->error('Failed to check for update, check the logs for more information.');
return self::FAILURE;
}
// Note: Cache for 13 hours, because the command runs twice daily (every 12 hours).
Cache::put('latest_version', $latestVersion, 60 * 60 * 12);
return self::SUCCESS;
}
}
================================================
FILE: app/Console/Commands/SelfHost/SelfHostDatabaseConsistency.php
================================================
<?php
declare(strict_types=1);
namespace App\Console\Commands\SelfHost;
use Illuminate\Console\Command;
use Illuminate\Database\Query\Builder;
use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class SelfHostDatabaseConsistency extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'self-host:database-consistency';
/**
* The console command description.
*
* @var string
*/
protected $description = '';
/**
* Execute the console command.
*/
public function handle(): int
{
$hadAProblem = false;
// Task need to be part of project in time entries
$problems = DB::table('time_entries')
->select(['time_entries.id as id'])
->join('tasks', 'time_entries.task_id', '=', 'tasks.id')
->where('tasks.project_id', '!=', DB::raw('time_entries.project_id'))
->get();
$this->logProblems($problems, 'Time entries have a task that does not belong to the project of the time entry', $hadAProblem);
// Client id is the client id of the project
$problems = DB::table('time_entries')
->select(['time_entries.id as id'])
->join('projects', 'time_entries.project_id', '=', 'projects.id')
->where(DB::raw('coalesce(projects.client_id::varchar, \'\')'), '!=', DB::raw('coalesce(time_entries.client_id::varchar, \'\')'))
->get();
$this->logProblems($problems, 'Time entries have a client that does not match the client of the project', $hadAProblem);
// Client id can only be not null if the project id is not null
$problems = DB::table('time_entries')
->select(['time_entries.id as id'])
->whereNotNull('client_id')
->whereNull('project_id')
->get();
$this->logProblems($problems, 'Time entries have a client but no project', $hadAProblem);
// Every user needs to be a member of at least one organization
$problems = DB::table('users')
->select(['users.id as id'])
->leftJoin('members', 'users.id', '=', 'members.user_id')
->whereNull('members.id')
->get();
$this->logProblems($problems, 'Users are not member of any organization', $hadAProblem);
// Every organization needs at least an owner
$problems = DB::table('organizations')
->select(['organizations.id as id'])
->leftJoin('members', function (JoinClause $join): void {
$join->on('organizations.id', '=', 'members.organization_id')
->where('members.role', '=', 'owner');
})
->whereNull('members.id')
->get();
$this->logProblems($problems, 'Organizations without an owner', $hadAProblem);
// Every member can only have one running time entry
$problems = DB::table('time_entries')
->select(['user_id as id'])
->whereNull('end')
->groupBy('user_id')
->havingRaw('count(*) > 1')
->get(['user_id', DB::raw('count(*) as count')]);
$this->logProblems($problems, 'Users with more than one running time entry', $hadAProblem);
// Users have a current organization that they are not a member of
$problems = DB::table('users')
->select(['users.id as id'])
->whereNotNull('current_team_id')
->whereNotIn('current_team_id', function (Builder $query): void {
$query->select('organization_id')
->from('members')
->whereColumn('members.user_id', 'users.id');
})->get();
$this->logProblems($problems, 'Users have a current organization that they are not a member of', $hadAProblem);
return $hadAProblem ? self::FAILURE : self::SUCCESS;
}
/**
* @param Collection<int, \stdClass> $problems
*/
private function logProblems(Collection $problems, string $message, bool &$hadAProblem): void
{
$message = 'Consistency problem: '.$message;
if ($problems->isNotEmpty()) {
$ids = $problems->pluck('id');
$hadAProblem = true;
Log::error($message, [
'ids' => $ids,
]);
$error = $message;
foreach ($ids as $id) {
$error .= "\n - ".$id;
}
$this->error($error);
}
}
}
================================================
FILE: app/Console/Commands/SelfHost/SelfHostGenerateKeysCommand.php
================================================
<?php
declare(strict_types=1);
namespace App\Console\Commands\SelfHost;
use Illuminate\Console\Command;
use Illuminate\Encryption\Encrypter;
use Illuminate\Support\Str;
use phpseclib3\Crypt\RSA;
class SelfHostGenerateKeysCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'self-host:generate-keys
{ --length=4096 : The length of the passport private key }
{ --multi-line : Whether to output the keys in multiple lines }
{ --format=env : The format of the output (env, yaml) }';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Generate random keys for the env variables.';
/**
* Execute the console command.
*/
public function handle(): int
{
$format = $this->option('format');
$key = RSA::createKey((int) $this->option('length'));
$multiLine = (bool) $this->option('multi-line');
$publicKey = (string) $key->getPublicKey();
$privateKey = (string) $key;
$appKey = 'base64:'.base64_encode(Encrypter::generateKey(config('app.cipher')));
if ($format === 'env') {
$this->line('APP_KEY="'.$appKey.'"');
if ($multiLine) {
$this->line('PASSPORT_PRIVATE_KEY="'.Str::replace("\r\n", "\n", $privateKey).'"');
$this->line('PASSPORT_PUBLIC_KEY="'.Str::replace("\r\n", "\n", $publicKey).'"');
} else {
$this->line('PASSPORT_PRIVATE_KEY="'.Str::replace("\r\n", '\n', $privateKey).'"');
$this->line('PASSPORT_PUBLIC_KEY="'.Str::replace("\r\n", '\n', $publicKey).'"');
}
} elseif ($format === 'yaml') {
$this->line('APP_KEY: "'.$appKey.'"');
$this->line("PASSPORT_PRIVATE_KEY: |\n ".Str::replace("\r\n", "\n ", $privateKey));
$this->line("PASSPORT_PUBLIC_KEY: |\n ".Str::replace("\r\n", "\n ", $publicKey));
} else {
$this->error('Invalid format');
return self::FAILURE;
}
return self::SUCCESS;
}
}
================================================
FILE: app/Console/Commands/SelfHost/SelfHostTelemetryCommand.php
================================================
<?php
declare(strict_types=1);
namespace App\Console\Commands\SelfHost;
use App\Service\ApiService;
use Illuminate\Console\Command;
class SelfHostTelemetryCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'self-host:telemetry';
/**
* The console command description.
*
* @var string
*/
protected $description = '';
/**
* Execute the console command.
*/
public function handle(): int
{
$apiService = app(ApiService::class);
$success = $apiService->telemetry();
if (! $success) {
$this->error('Failed to send telemetry data, check the logs for more information.');
return self::FAILURE;
}
return self::SUCCESS;
}
}
================================================
FILE: app/Console/Commands/Test/TestEmailCommand.php
================================================
<?php
declare(strict_types=1);
namespace App\Console\Commands\Test;
use Illuminate\Console\Command;
use Illuminate\Mail\Message;
use Illuminate\Support\Facades\Mail;
class TestEmailCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'test:email { email : Email address to send the email to }';
/**
* The console command description.
*
* @var string
*/
protected $description = 'This test command sends an email.';
/**
* Execute the console command.
*/
public function handle(): int
{
$email = $this->argument('email');
Mail::raw('Hello World!', function (Message $message) use ($email): void {
$message->to($email)
->subject('Test Email')
->html('<h1>Hello World!</h1>');
});
return self::SUCCESS;
}
}
================================================
FILE: app/Console/Commands/Test/TestJobCommand.php
================================================
<?php
declare(strict_types=1);
namespace App\Console\Commands\Test;
use App\Jobs\Test\TestJob;
use App\Models\User;
use Illuminate\Console\Command;
class TestJobCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'test:job {--fail}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'This test command start an async job.';
/**
* Execute the console command.
*/
public function handle(): int
{
$user = User::firstOrFail();
$fail = (bool) $this->option('fail');
TestJob::dispatch($user, 'Test job message.', $fail);
return self::SUCCESS;
}
}
================================================
FILE: app/Console/Commands/Test/TestOutputCommand.php
================================================
<?php
declare(strict_types=1);
namespace App\Console\Commands\Test;
use Illuminate\Console\Command;
class TestOutputCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'test:output';
/**
* The console command description.
*
* @var string
*/
protected $description = 'This test command outputs some text.';
/**
* Execute the console command.
*/
public function handle(): int
{
$this->info('Test command output');
$this->error('Test command output error');
return self::SUCCESS;
}
}
================================================
FILE: app/Console/Commands/TimeEntry/TimeEntrySendStillRunningMailsCommand.php
================================================
<?php
declare(strict_types=1);
namespace App\Console\Commands\TimeEntry;
use App\Mail\TimeEntryStillRunningMail;
use App\Models\TimeEntry;
use App\Models\User;
use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Mail;
class TimeEntrySendStillRunningMailsCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'time-entry:send-still-running-mails '.
' { --dry-run : Do not actually send emails or save anything to the database, just output what would happen }';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Sends emails to users who have running time entries for more than 8 hours.';
/**
* Execute the console command.
*/
public function handle(): int
{
$this->comment('Sending still running time entry emails...');
$dryRun = (bool) $this->option('dry-run');
if ($dryRun) {
$this->comment('Running in dry-run mode. No emails will be sent and nothing will be saved to the database.');
}
$sentMails = 0;
TimeEntry::query()
->whereNull('end')
->where('start', '<', now()->subHours(8))
->whereNull('still_active_email_sent_at')
->with([
'user',
])
->whereHas('user', function (Builder $query): void {
/** @var Builder<User> $query */
$query->where('is_placeholder', '=', false);
})
->orderBy('created_at', 'asc')
->chunk(500, function (Collection $timeEntries) use ($dryRun, &$sentMails): void {
/** @var Collection<int, TimeEntry> $timeEntries */
foreach ($timeEntries as $timeEntry) {
$user = $timeEntry->user;
$this->info('Start sending email to user "'.$user->email.'" ('.$user->getKey().') for time entry '.$timeEntry->getKey());
$sentMails++;
if (! $dryRun) {
Mail::to($user->email)
->queue(new TimeEntryStillRunningMail($timeEntry, $user));
$timeEntry->still_active_email_sent_at = Carbon::now();
$timeEntry->save();
}
}
});
$this->comment('Finished sending '.$sentMails.' still running time entry emails...');
return self::SUCCESS;
}
}
================================================
FILE: app/Console/Kernel.php
================================================
<?php
declare(strict_types=1);
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* Define the application's command schedule.
*/
protected function schedule(Schedule $schedule): void
{
$schedule->command('time-entry:send-still-running-mails')
->when(fn (): bool => config('scheduling.tasks.time_entry_send_still_running_mails'))
->everyTenMinutes();
$schedule->command('auth:send-mails-expiring-api-tokens')
->when(fn (): bool => config('scheduling.tasks.auth_send_mails_expiring_api_tokens'))
->everyTenMinutes();
if (config('app.key') && (config('scheduling.tasks.self_hosting_check_for_update') || config('scheduling.tasks.self_hosting_telemetry'))) {
// Convert string to a stable integer for seeding
/** @var int $seed Take the first 8 hex chars → 32-bit int */
$seed = hexdec(substr(hash('md5', config('app.key')), 0, 8));
$seed = abs($seed); // Ensure it's positive
mt_srand($seed);
$firstHour = mt_rand(0, 23);
$secondHour = ($firstHour + 12) % 24;
$minuteOffset = mt_rand(0, 59);
mt_srand(null); // Reset the random number generator
if (config('scheduling.tasks.self_hosting_check_for_update')) {
$schedule->command('self-host:check-for-update')
->twiceDailyAt($firstHour, $secondHour, $minuteOffset);
}
if (config('scheduling.tasks.self_hosting_telemetry')) {
$schedule->command('self-host:telemetry')
->twiceDailyAt($firstHour, $secondHour, $minuteOffset);
}
}
$schedule->command('self-host:database-consistency')
->when(fn (): bool => config('scheduling.tasks.self_hosting_database_consistency'))
->everySixHours();
}
/**
* Register the commands for the application.
*/
protected function commands(): void
{
$this->load(__DIR__.'/Commands');
}
}
================================================
FILE: app/Enums/CurrencyFormat.php
================================================
<?php
declare(strict_types=1);
namespace App\Enums;
use Datomatic\LaravelEnumHelper\LaravelEnumHelper;
enum CurrencyFormat: string
{
use LaravelEnumHelper;
case ISOCodeBeforeWithSpace = 'iso-code-before-with-space';
case ISOCodeAfterWithSpace = 'iso-code-after-with-space';
case SymbolBefore = 'symbol-before';
case SymbolAfter = 'symbol-after';
case SymbolBeforeWithSpace = 'symbol-before-with-space';
case SymbolAfterWithSpace = 'symbol-after-with-space';
/**
* @return array<string, string>
*/
public static function toSelectArray(): array
{
$selectArray = [];
foreach (self::values() as $value) {
$selectArray[(string) $value] = (string) __('enum.currency_format.'.$value);
}
return $selectArray;
}
}
================================================
FILE: app/Enums/DateFormat.php
================================================
<?php
declare(strict_types=1);
namespace App\Enums;
use Datomatic\LaravelEnumHelper\LaravelEnumHelper;
enum DateFormat: string
{
use LaravelEnumHelper;
case PointSeparatedDMYYYY = 'point-separated-d-m-yyyy';
case SlashSeparatedMMDDYYYY = 'slash-separated-mm-dd-yyyy';
case SlashSeparatedDDMMYYYY = 'slash-separated-dd-mm-yyyy';
case HyphenSeparatedDDMMYYY = 'hyphen-separated-dd-mm-yyyy';
case HyphenSeparatedMMDDDYYYY = 'hyphen-separated-mm-dd-yyyy';
case HyphenSeparatedYYYYMMDD = 'hyphen-separated-yyyy-mm-dd';
public function toCarbonFormat(): string
{
return match ($this->value) {
self::PointSeparatedDMYYYY->value => 'j.n.Y',
self::SlashSeparatedMMDDYYYY->value => 'm/d/Y',
self::SlashSeparatedDDMMYYYY->value => 'd/m/Y',
self::HyphenSeparatedDDMMYYY->value => 'd-m-Y',
self::HyphenSeparatedMMDDDYYYY->value => 'm-d-Y',
self::HyphenSeparatedYYYYMMDD->value => 'Y-m-d',
};
}
/**
* @return array<string, string>
*/
public static function toSelectArray(): array
{
$selectArray = [];
foreach (self::values() as $value) {
$selectArray[(string) $value] = (string) __('enum.date_format.'.$value);
}
return $selectArray;
}
}
================================================
FILE: app/Enums/ExportFormat.php
================================================
<?php
declare(strict_types=1);
namespace App\Enums;
use Maatwebsite\Excel\Excel;
enum ExportFormat: string
{
case CSV = 'csv';
case PDF = 'pdf';
case XLSX = 'xlsx';
case ODS = 'ods';
public function getFileExtension(): string
{
return match ($this) {
self::CSV => 'csv',
self::PDF => 'pdf',
self::XLSX => 'xlsx',
self::ODS => 'ods',
};
}
public function getExportPackageType(): string
{
return match ($this) {
self::CSV => Excel::CSV,
self::PDF => Excel::MPDF,
self::XLSX => Excel::XLSX,
self::ODS => Excel::ODS,
};
}
}
================================================
FILE: app/Enums/IntervalFormat.php
================================================
<?php
declare(strict_types=1);
namespace App\Enums;
use Datomatic\LaravelEnumHelper\LaravelEnumHelper;
enum IntervalFormat: string
{
use LaravelEnumHelper;
case Decimal = 'decimal';
case HoursMinutes = 'hours-minutes';
case HoursMinutesColonSeparated = 'hours-minutes-colon-separated';
case HoursMinutesSecondsColonSeparated = 'hours-minutes-seconds-colon-separated';
/**
* @return array<string, string>
*/
public static function toSelectArray(): array
{
$selectArray = [];
foreach (self::values() as $value) {
$selectArray[(string) $value] = (string) __('enum.interval_format.'.$value);
}
return $selectArray;
}
}
================================================
FILE: app/Enums/NumberFormat.php
================================================
<?php
declare(strict_types=1);
namespace App\Enums;
use Datomatic\LaravelEnumHelper\LaravelEnumHelper;
/**
* @info https://en.wikipedia.org/wiki/Decimal_separator
*/
enum NumberFormat: string
{
use LaravelEnumHelper;
case ThousandsPointDecimalComma = 'point-comma';
case ThousandsCommaDecimalPoint = 'comma-point';
case ThousandsSpaceDecimalComma = 'space-comma';
case ThousandsSpaceDecimalPoint = 'space-point';
case ThousandsApostropheDecimalPoint = 'apostrophe-point';
/**
* @return array<string, string>
*/
public static function toSelectArray(): array
{
$selectArray = [];
foreach (self::values() as $value) {
$selectArray[(string) $value] = (string) __('enum.number_format.'.$value);
}
return $selectArray;
}
}
================================================
FILE: app/Enums/Role.php
================================================
<?php
declare(strict_types=1);
namespace App\Enums;
enum Role: string
{
case Owner = 'owner';
case Admin = 'admin';
case Manager = 'manager';
case Employee = 'employee';
case Placeholder = 'placeholder';
}
================================================
FILE: app/Enums/TimeEntryAggregationType.php
================================================
<?php
declare(strict_types=1);
namespace App\Enums;
use Datomatic\LaravelEnumHelper\LaravelEnumHelper;
enum TimeEntryAggregationType: string
{
use LaravelEnumHelper;
case Day = 'day';
case Week = 'week';
case Month = 'month';
case Year = 'year';
case User = 'user';
case Project = 'project';
case Task = 'task';
case Client = 'client';
case Billable = 'billable';
case Description = 'description';
case Tag = 'tag';
public static function fromInterval(TimeEntryAggregationTypeInterval $timeEntryAggregationTypeInterval): TimeEntryAggregationType
{
return match ($timeEntryAggregationTypeInterval) {
TimeEntryAggregationTypeInterval::Day => TimeEntryAggregationType::Day,
TimeEntryAggregationTypeInterval::Week => TimeEntryAggregationType::Week,
TimeEntryAggregationTypeInterval::Month => TimeEntryAggregationType::Month,
TimeEntryAggregationTypeInterval::Year => TimeEntryAggregationType::Year,
};
}
public function toInterval(): ?TimeEntryAggregationTypeInterval
{
return match ($this) {
TimeEntryAggregationType::Day => TimeEntryAggregationTypeInterval::Day,
TimeEntryAggregationType::Week => TimeEntryAggregationTypeInterval::Week,
TimeEntryAggregationType::Month => TimeEntryAggregationTypeInterval::Month,
TimeEntryAggregationType::Year => TimeEntryAggregationTypeInterval::Year,
default => null
};
}
}
================================================
FILE: app/Enums/TimeEntryAggregationTypeInterval.php
================================================
<?php
declare(strict_types=1);
namespace App\Enums;
enum TimeEntryAggregationTypeInterval: string
{
case Day = 'day';
case Week = 'week';
case Month = 'month';
case Year = 'year';
}
================================================
FILE: app/Enums/TimeEntryRoundingType.php
================================================
<?php
declare(strict_types=1);
namespace App\Enums;
use Datomatic\LaravelEnumHelper\LaravelEnumHelper;
enum TimeEntryRoundingType: string
{
use LaravelEnumHelper;
case Up = 'up';
case Down = 'down';
case Nearest = 'nearest';
}
================================================
FILE: app/Enums/TimeFormat.php
================================================
<?php
declare(strict_types=1);
namespace App\Enums;
use Datomatic\LaravelEnumHelper\LaravelEnumHelper;
enum TimeFormat: string
{
use LaravelEnumHelper;
case TwelveHours = '12-hours';
case TwentyFourHours = '24-hours';
/**
* @return array<string, string>
*/
public static function toSelectArray(): array
{
$selectArray = [];
foreach (self::values() as $value) {
$selectArray[(string) $value] = (string) __('enum.time_format.'.$value);
}
return $selectArray;
}
}
================================================
FILE: app/Enums/Weekday.php
================================================
<?php
declare(strict_types=1);
namespace App\Enums;
use Datomatic\LaravelEnumHelper\LaravelEnumHelper;
use Illuminate\Support\Carbon;
enum Weekday: string
{
use LaravelEnumHelper;
case Monday = 'monday';
case Tuesday = 'tuesday';
case Wednesday = 'wednesday';
case Thursday = 'thursday';
case Friday = 'friday';
case Saturday = 'saturday';
case Sunday = 'sunday';
public function toEndOfWeek(): self
{
return match ($this) {
Weekday::Monday => Weekday::Sunday,
Weekday::Tuesday => Weekday::Monday,
Weekday::Wednesday => Weekday::Tuesday,
Weekday::Thursday => Weekday::Wednesday,
Weekday::Friday => Weekday::Thursday,
Weekday::Saturday => Weekday::Friday,
Weekday::Sunday => Weekday::Saturday,
};
}
public function carbonWeekDay(): int
{
return match ($this) {
Weekday::Monday => Carbon::MONDAY,
Weekday::Tuesday => Carbon::TUESDAY,
Weekday::Wednesday => Carbon::WEDNESDAY,
Weekday::Thursday => Carbon::THURSDAY,
Weekday::Friday => Carbon::FRIDAY,
Weekday::Saturday => Carbon::SATURDAY,
Weekday::Sunday => Carbon::SUNDAY,
};
}
/**
* @return array<string, string>
*/
public static function toSelectArray(): array
{
return [
Weekday::Monday->value => __('enum.weekday.'.Weekday::Monday->value),
Weekday::Tuesday->value => __('enum.weekday.'.Weekday::Tuesday->value),
Weekday::Wednesday->value => __('enum.weekday.'.Weekday::Wednesday->value),
Weekday::Thursday->value => __('enum.weekday.'.Weekday::Thursday->value),
Weekday::Friday->value => __('enum.weekday.'.Weekday::Friday->value),
Weekday::Saturday->value => __('enum.weekday.'.Weekday::Saturday->value),
Weekday::Sunday->value => __('enum.weekday.'.Weekday::Sunday->value),
];
}
}
================================================
FILE: app/Events/AfterCreateOrganization.php
================================================
<?php
declare(strict_types=1);
namespace App\Events;
use App\Models\Organization;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
/**
* This event is fired after an organization has been created.
* This event does NOT fire when an organization is created as part of a registration.
*/
class AfterCreateOrganization
{
use Dispatchable;
use SerializesModels;
public Organization $organization;
public function __construct(Organization $organization)
{
$this->organization = $organization;
}
}
================================================
FILE: app/Events/BeforeOrganizationDeletion.php
================================================
<?php
declare(strict_types=1);
namespace App\Events;
use App\Models\Organization;
use Illuminate\Foundation\Events\Dispatchable;
class BeforeOrganizationDeletion
{
use Dispatchable;
public Organization $organization;
public function __construct(Organization $organization)
{
$this->organization = $organization;
}
}
================================================
FILE: app/Events/DatabaseSeederAfterSeed.php
================================================
<?php
declare(strict_types=1);
namespace App\Events;
use Illuminate\Foundation\Events\Dispatchable;
class DatabaseSeederAfterSeed
{
use Dispatchable;
public function __construct() {}
}
================================================
FILE: app/Events/DatabaseSeederBeforeDelete.php
================================================
<?php
declare(strict_types=1);
namespace App\Events;
use Illuminate\Foundation\Events\Dispatchable;
class DatabaseSeederBeforeDelete
{
use Dispatchable;
public function __construct() {}
}
================================================
FILE: app/Events/MemberMadeToPlaceholder.php
================================================
<?php
declare(strict_types=1);
namespace App\Events;
use App\Models\Member;
use App\Models\Organization;
use Illuminate\Foundation\Events\Dispatchable;
class MemberMadeToPlaceholder
{
use Dispatchable;
public Organization $organization;
public Member $member;
public function __construct(Member $member, Organization $organization)
{
$this->member = $member;
$this->organization = $organization;
}
}
================================================
FILE: app/Events/MemberRemoved.php
================================================
<?php
declare(strict_types=1);
namespace App\Events;
use App\Models\Member;
use App\Models\Organization;
use Illuminate\Foundation\Events\Dispatchable;
class MemberRemoved
{
use Dispatchable;
public Organization $organization;
public Member $member;
public function __construct(Member $member, Organization $organization)
{
$this->member = $member;
$this->organization = $organization;
}
}
================================================
FILE: app/Events/NewsletterRegistered.php
================================================
<?php
declare(strict_types=1);
namespace App\Events;
use Illuminate\Foundation\Events\Dispatchable;
class NewsletterRegistered
{
use Dispatchable;
public string $name;
public string $email;
public string $id;
/**
* Create a new event instance.
*/
public function __construct(string $name, string $email, string $id)
{
$this->name = $name;
$this->email = $email;
$this->id = $id;
}
}
================================================
FILE: app/Exceptions/Api/ApiException.php
================================================
<?php
declare(strict_types=1);
namespace App\Exceptions\Api;
use Exception;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use LogicException;
abstract class ApiException extends Exception
{
public const string KEY = 'api_exception';
public function __construct()
{
parent::__construct(static::KEY);
}
/**
* Render the exception into an HTTP response.
*/
public function render(Request $request): JsonResponse
{
return response()
->json([
'error' => true,
'key' => $this->getKey(),
'message' => $this->getTranslatedMessage(),
], 400);
}
/**
* Get the key for the exception.
*/
public function getKey(): string
{
$key = static::KEY;
if ($key === ApiException::KEY) {
throw new LogicException('API exceptions need the KEY constant defined.');
}
return $key;
}
/**
* Get the translated message for the exception.
*/
public function getTranslatedMessage(): string
{
return __('exceptions.api.'.$this->getKey());
}
/**
* Report the exception.
*
* @return bool true means the exception handler will not report it again
*/
public function report(): bool
{
// TODO: temporary activated
return false;
}
}
================================================
FILE: app/Exceptions/Api/CanNotDeleteUserWhoIsOwnerOfOrganizationWithMultipleMembers.php
================================================
<?php
declare(strict_types=1);
namespace App\Exceptions\Api;
class CanNotDeleteUserWhoIsOwnerOfOrganizationWithMultipleMembers extends ApiException
{
public const string KEY = 'can_not_delete_user_who_is_owner_of_organization_with_multiple_members';
}
================================================
FILE: app/Exceptions/Api/CanNotRemoveOwnerFromOrganization.php
================================================
<?php
declare(strict_types=1);
namespace App\Exceptions\Api;
class CanNotRemoveOwnerFromOrganization extends ApiException
{
public const string KEY = 'can_not_remove_owner_from_organization';
}
================================================
FILE: app/Exceptions/Api/ChangingRoleOfPlaceholderIsNotAllowed.php
================================================
<?php
declare(strict_types=1);
namespace App\Exceptions\Api;
class ChangingRoleOfPlaceholderIsNotAllowed extends ApiException
{
public const string KEY = 'changing_role_of_placeholder_is_not_allowed';
}
================================================
FILE: app/Exceptions/Api/ChangingRoleToPlaceholderIsNotAllowed.php
================================================
<?php
declare(strict_types=1);
namespace App\Exceptions\Api;
class ChangingRoleToPlaceholderIsNotAllowed extends ApiException
{
public const string KEY = 'changing_role_to_placeholder_is_not_allowed';
}
================================================
FILE: app/Exceptions/Api/EntityStillInUseApiException.php
================================================
<?php
declare(strict_types=1);
namespace App\Exceptions\Api;
class EntityStillInUseApiException extends ApiException
{
private string $modelToDelete;
private string $modelInUse;
public function __construct(string $modelToDelete, string $modelInUse)
{
parent::__construct();
$this->modelToDelete = $modelToDelete;
$this->modelInUse = $modelInUse;
}
public const string KEY = 'entity_still_in_use';
/**
* Get the translated message for the exception.
*/
#[\Override]
public function getTranslatedMessage(): string
{
return __('exceptions.api.'.$this->getKey(), [
'modelToDelete' => __('validation.entities.'.$this->modelToDelete),
'modelInUse' => __('validation.entities.'.$this->modelInUse),
]);
}
}
================================================
FILE: app/Exceptions/Api/FeatureIsNotAvailableInFreePlanApiException.php
================================================
<?php
declare(strict_types=1);
namespace App\Exceptions\Api;
class FeatureIsNotAvailableInFreePlanApiException extends ApiException
{
public const string KEY = 'feature_is_not_available_in_free_plan';
}
================================================
FILE: app/Exceptions/Api/InactiveUserCanNotBeUsedApiException.php
================================================
<?php
declare(strict_types=1);
namespace App\Exceptions\Api;
class InactiveUserCanNotBeUsedApiException extends ApiException
{
public const string KEY = 'inactive_user_can_not_be_used';
}
================================================
FILE: app/Exceptions/Api/InvitationForTheEmailAlreadyExistsApiException.php
================================================
<?php
declare(strict_types=1);
namespace App\Exceptions\Api;
class InvitationForTheEmailAlreadyExistsApiException extends ApiException
{
public const string KEY = 'invitation_for_the_email_already_exists';
}
================================================
FILE: app/Exceptions/Api/OnlyOwnerCanChangeOwnership.php
================================================
<?php
declare(strict_types=1);
namespace App\Exceptions\Api;
class OnlyOwnerCanChangeOwnership extends ApiException
{
public const string KEY = 'only_owner_can_change_ownership';
}
================================================
FILE: app/Exceptions/Api/OnlyPlaceholdersCanBeMergedIntoAnotherMember.php
================================================
<?php
declare(strict_types=1);
namespace App\Exceptions\Api;
class OnlyPlaceholdersCanBeMergedIntoAnotherMember extends ApiException
{
public const string KEY = 'only_placeholders_can_be_merged_into_another_member';
}
================================================
FILE: app/Exceptions/Api/OrganizationHasNoSubscriptionButMultipleMembersException.php
================================================
<?php
declare(strict_types=1);
namespace App\Exceptions\Api;
class OrganizationHasNoSubscriptionButMultipleMembersException extends ApiException
{
public const string KEY = 'organization_has_no_subscription_but_multiple_members';
}
================================================
FILE: app/Exceptions/Api/OrganizationNeedsAtLeastOneOwner.php
================================================
<?php
declare(strict_types=1);
namespace App\Exceptions\Api;
class OrganizationNeedsAtLeastOneOwner extends ApiException
{
public const string KEY = 'organization_needs_at_least_one_owner';
}
================================================
FILE: app/Exceptions/Api/OverlappingTimeEntryApiException.php
================================================
<?php
declare(strict_types=1);
namespace App\Exceptions\Api;
class OverlappingTimeEntryApiException extends ApiException
{
public const string KEY = 'overlapping_time_entry';
}
================================================
FILE: app/Exceptions/Api/PdfRendererIsNotConfiguredException.php
================================================
<?php
declare(strict_types=1);
namespace App\Exceptions\Api;
class PdfRendererIsNotConfiguredException extends ApiException
{
public const string KEY = 'pdf_renderer_is_not_configured';
}
================================================
FILE: app/Exceptions/Api/PersonalAccessClientIsNotConfiguredException.php
================================================
<?php
declare(strict_types=1);
namespace App\Exceptions\Api;
class PersonalAccessClientIsNotConfiguredException extends ApiException
{
public const string KEY = 'personal_access_client_is_not_configured';
}
================================================
FILE: app/Exceptions/Api/ThisPlaceholderCanNotBeInvitedUseTheMergeToolInsteadException.php
================================================
<?php
declare(strict_types=1);
namespace App\Exceptions\Api;
class ThisPlaceholderCanNotBeInvitedUseTheMergeToolInsteadException extends ApiException
{
public const string KEY = 'this_placeholder_can_not_be_invited_use_the_merge_tool_instead_api_exception';
}
================================================
FILE: app/Exceptions/Api/TimeEntryCanNotBeRestartedApiException.php
================================================
<?php
declare(strict_types=1);
namespace App\Exceptions\Api;
class TimeEntryCanNotBeRestartedApiException extends ApiException
{
public const string KEY = 'time_entry_can_not_be_restarted';
}
================================================
FILE: app/Exceptions/Api/TimeEntryStillRunningApiException.php
================================================
<?php
declare(strict_types=1);
namespace App\Exceptions\Api;
class TimeEntryStillRunningApiException extends ApiException
{
public const string KEY = 'time_entry_still_running';
}
================================================
FILE: app/Exceptions/Api/UserIsAlreadyMemberOfOrganizationApiException.php
================================================
<?php
declare(strict_types=1);
namespace App\Exceptions\Api;
class UserIsAlreadyMemberOfOrganizationApiException extends ApiException
{
public const string KEY = 'user_is_already_member_of_organization';
}
================================================
FILE: app/Exceptions/Api/UserIsAlreadyMemberOfProjectApiException.php
================================================
<?php
declare(strict_types=1);
namespace App\Exceptions\Api;
class UserIsAlreadyMemberOfProjectApiException extends ApiException
{
public const string KEY = 'user_is_already_member_of_project';
}
================================================
FILE: app/Exceptions/Api/UserNotPlaceholderApiException.php
================================================
<?php
declare(strict_types=1);
namespace App\Exceptions\Api;
class UserNotPlaceholderApiException extends ApiException
{
public const string KEY = 'user_not_placeholder';
}
================================================
FILE: app/Exceptions/Handler.php
================================================
<?php
declare(strict_types=1);
namespace App\Exceptions;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Http\RedirectResponse;
use Symfony\Component\HttpFoundation\Response;
use Throwable;
class Handler extends ExceptionHandler
{
/**
* The list of the inputs that are never flashed to the session on validation exceptions.
*
* @var array<int, string>
*/
protected $dontFlash = [
'current_password',
'password',
'password_confirmation',
];
/**
* Register the exception handling callbacks for the application.
*/
public function register(): void
{
$this->reportable(function (Throwable $e): void {
//
});
}
public function render($request, Throwable $e): Response|RedirectResponse
{
$response = parent::render($request, $e);
if ($response->getStatusCode() === 419) {
return back()->with([
'message' => 'The page expired, please try again.',
]);
}
return $response;
}
}
================================================
FILE: app/Exceptions/MovedToApiException.php
================================================
<?php
declare(strict_types=1);
namespace App\Exceptions;
use Symfony\Component\HttpKernel\Exception\HttpException;
class MovedToApiException extends HttpException
{
public function __construct()
{
parent::__construct(403, 'Moved to API');
}
}
================================================
FILE: app/Extensions/Auditing/Resolvers/CustomIpAddressResolver.php
================================================
<?php
declare(strict_types=1);
namespace App\Extensions\Auditing\Resolvers;
use Illuminate\Support\Facades\Request;
use OwenIt\Auditing\Contracts\Auditable;
use OwenIt\Auditing\Contracts\Resolver;
class CustomIpAddressResolver implements Resolver
{
private static function anonymizeIpAddress(string $ipAddress): string
{
/** @source https://stackoverflow.com/a/48777412 */
return preg_replace(
['/\.\d*$/', '/[\da-f]*:[\da-f]*$/'],
['.0', '0:0'],
$ipAddress
);
}
public static function resolve(Auditable $auditable): string
{
$ip = $auditable->preloadedResolverData['ip_address'] ?? Request::ip();
if ($ip !== null) {
$ip = self::anonymizeIpAddress($ip);
}
return $ip;
}
}
================================================
FILE: app/Extensions/Fortify/CustomLoginResponse.php
================================================
<?php
declare(strict_types=1);
namespace App\Extensions\Fortify;
use Illuminate\Http\Request;
use Inertia\Inertia;
use Laravel\Fortify\Http\Responses\LoginResponse;
use Symfony\Component\HttpFoundation\Response;
class CustomLoginResponse extends LoginResponse
{
/**
* Create an HTTP response that represents the object.
*
* @param Request $request
*/
public function toResponse($request): Response
{
$redirectPath = session()->pull('url.intended', route('dashboard', [], false));
return $request->wantsJson()
? response()->json(['two_factor' => false])
: Inertia::location($redirectPath);
}
}
================================================
FILE: app/Extensions/Fortify/CustomTwoFactorLoginResponse.php
================================================
<?php
declare(strict_types=1);
namespace App\Extensions\Fortify;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Inertia\Inertia;
use Laravel\Fortify\Contracts\TwoFactorLoginResponse as TwoFactorLoginResponseContract;
use Symfony\Component\HttpFoundation\Response;
class CustomTwoFactorLoginResponse implements TwoFactorLoginResponseContract
{
/**
* Create an HTTP response that represents the object.
*
* @param Request $request
*/
public function toResponse($request): Response
{
$redirectPath = session()->pull('url.intended', route('dashboard', [], false));
return $request->wantsJson()
? new JsonResponse('', 204)
: Inertia::location($redirectPath);
}
}
================================================
FILE: app/Extensions/Scramble/ApiExceptionTypeToSchema.php
================================================
<?php
declare(strict_types=1);
namespace App\Extensions\Scramble;
use App\Exceptions\Api\ApiException;
use Dedoc\Scramble\Extensions\ExceptionToResponseExtension;
use Dedoc\Scramble\Support\Generator\Reference;
use Dedoc\Scramble\Support\Generator\Response;
use Dedoc\Scramble\Support\Generator\Schema;
use Dedoc\Scramble\Support\Generator\Types as OpenApiTypes;
use Dedoc\Scramble\Support\Type\ObjectType;
use Dedoc\Scramble\Support\Type\Type;
use Illuminate\Support\Str;
class ApiExceptionTypeToSchema extends ExceptionToResponseExtension
{
public function shouldHandle(Type $type): bool
{
return $type instanceof ObjectType
&& $type->isInstanceOf(ApiException::class);
}
public function toResponse(Type $type): Response
{
$validationResponseBodyType = (new OpenApiTypes\ObjectType)
->addProperty(
'error',
(new OpenApiTypes\BooleanType)
->setDescription('Whether the response is an error.')
)
->addProperty(
'key',
(new OpenApiTypes\StringType)
->setDescription('Error key.')
)
->addProperty(
'message',
(new OpenApiTypes\StringType)
->setDescription('Error message.')
)
->setRequired(['error', 'key', 'message']);
return Response::make(400)
->description('API exception')
->setContent(
'application/json',
Schema::fromType($validationResponseBodyType)
);
}
public function reference(ObjectType $type): Reference
{
return new Reference('responses', Str::start($type->name, '\\'), $this->components);
}
}
================================================
FILE: app/Extensions/Scramble/PaginatedResourceCollectionTypeToSchema.php
================================================
<?php
declare(strict_types=1);
namespace App\Extensions\Scramble;
use App\Http\Resources\PaginatedResourceCollection;
use App\Http\Resources\V1\TimeEntry\TimeEntryCollection;
use Dedoc\Scramble\Extensions\TypeToSchemaExtension;
use Dedoc\Scramble\Support\Generator\Response;
use Dedoc\Scramble\Support\Generator\Schema;
use Dedoc\Scramble\Support\Generator\Types\ArrayType;
use Dedoc\Scramble\Support\Generator\Types\BooleanType;
use Dedoc\Scramble\Support\Generator\Types\IntegerType;
use Dedoc\Scramble\Support\Generator\Types\ObjectType as OpenApiObjectType;
use Dedoc\Scramble\Support\Generator\Types\StringType;
use Dedoc\Scramble\Support\Type\Generic;
use Dedoc\Scramble\Support\Type\ObjectType;
use Dedoc\Scramble\Support\Type\Type;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Resources\Json\JsonResource;
class PaginatedResourceCollectionTypeToSchema extends TypeToSchemaExtension
{
public function shouldHandle(Type $type): bool
{
return $type instanceof ObjectType
&& $type->isInstanceOf(PaginatedResourceCollection::class);
}
public function toSchema(Type $type): ?OpenApiObjectType
{
/** @var Type|null $collectingClassType */
$collectingClassType = $type->templateTypes[0] ?? null;
if (! $collectingClassType instanceof ObjectType) {
return null;
}
if (! $collectingClassType->isInstanceOf(JsonResource::class) && ! $collectingClassType->isInstanceOf(Model::class)) {
return null;
}
$collectingType = $this->openApiTransformer->transform($collectingClassType);
$newType = new OpenApiObjectType;
$newType->addProperty('data', (new ArrayType)->setItems($collectingType));
if ($type instanceof ObjectType && $type->isInstanceOf(TimeEntryCollection::class)) {
$newType->addProperty(
'meta',
(new OpenApiObjectType)
->addProperty('total', (new IntegerType)->setDescription('Total number of items being paginated.'))
->setRequired(['total'])
);
$newType->setRequired(['data', 'meta']);
} else {
$newType->addProperty(
'links',
(new OpenApiObjectType)
->addProperty('first', (new StringType)->nullable(true))
->addProperty('last', (new StringType)->nullable(true))
->addProperty('prev', (new StringType)->nullable(true))
->addProperty('next', (new StringType)->nullable(true))
->setRequired(['first', 'last', 'prev', 'next'])
);
$newType->addProperty(
'meta',
(new OpenApiObjectType)
->addProperty('current_page', new IntegerType)
->addProperty('from', (new IntegerType)->nullable(true))
->addProperty('last_page', new IntegerType)
->addProperty('links', (new ArrayType)->setItems(
(new OpenApiObjectType)
->addProperty('url', (new StringType)->nullable(true))
->addProperty('label', new StringType)
->addProperty('active', new BooleanType)
->setRequired(['url', 'label', 'active'])
)->setDescription('Generated paginator links.'))
->addProperty('path', (new StringType)->nullable(true)->setDescription('Base path for paginator generated URLs.'))
->addProperty('per_page', (new IntegerType)->setDescription('Number of items shown per page.'))
->addProperty('to', (new IntegerType)->nullable(true)->setDescription('Number of the last item in the slice.'))
->addProperty('total', (new IntegerType)->setDescription('Total number of items being paginated.'))
->setRequired(['current_page', 'from', 'last_page', 'links', 'path', 'per_page', 'to', 'total'])
);
$newType->setRequired(['data', 'links', 'meta']);
}
return $newType;
}
/**
* @param Generic $type
*/
public function toResponse(Type $type): ?Response
{
/** @var ObjectType|null $collectingClassType */
$collectingClassType = $type->templateTypes[0] ?? null;
if (! $collectingClassType instanceof ObjectType) {
return null;
}
$type = $this->toSchema($type);
return Response::make(200)
->description('Paginated set of `'.$this->components->uniqueSchemaName($collectingClassType->name).'`')
->setContent('application/json', Schema::fromType($type));
}
}
================================================
FILE: app/Filament/Resources/AuditResource/Pages/CreateAudit.php
================================================
<?php
declare(strict_types=1);
namespace App\Filament\Resources\AuditResource\Pages;
use App\Filament\Resources\AuditResource;
use Filament\Resources\Pages\CreateRecord;
class CreateAudit extends CreateRecord
{
protected static string $resource = AuditResource::class;
}
================================================
FILE: app/Filament/Resources/AuditResource/Pages/ListAudits.php
================================================
<?php
declare(strict_types=1);
namespace App\Filament\Resources\AuditResource\Pages;
use App\Filament\Resources\AuditResource;
use Filament\Resources\Pages\ListRecords;
class ListAudits extends ListRecords
{
protected static string $resource = AuditResource::class;
protected function getHeaderActions(): array
{
return [];
}
}
================================================
FILE: app/Filament/Resources/AuditResource/Pages/ViewAudit.php
================================================
<?php
declare(strict_types=1);
namespace App\Filament\Resources\AuditResource\Pages;
use App\Filament\Resources\AuditResource;
use Filament\Resources\Pages\ViewRecord;
class ViewAudit extends ViewRecord
{
protected static string $resource = AuditResource::class;
}
================================================
FILE: app/Filament/Resources/AuditResource.php
================================================
<?php
declare(strict_types=1);
namespace App\Filament\Resources;
use App\Filament\Resources\AuditResource\Pages;
use App\Models\Audit;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Table;
use Illuminate\Support\Str;
use Novadaemon\FilamentPrettyJson\Form\PrettyJsonField;
class AuditResource extends Resource
{
protected static ?string $model = Audit::class;
protected static ?string $navigationIcon = 'heroicon-o-archive-box';
protected static ?string $navigationGroup = 'System';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('user_type')
->maxLength(255),
Forms\Components\TextInput::make('user_id'),
Forms\Components\TextInput::make('event')
->required()
->maxLength(255),
Forms\Components\TextInput::make('auditable_type')
->required()
->maxLength(255),
Forms\Components\TextInput::make('auditable_id')
->required(),
PrettyJsonField::make('old_values'),
PrettyJsonField::make('new_values'),
Forms\Components\Textarea::make('url'),
Forms\Components\TextInput::make('ip_address'),
Forms\Components\TextInput::make('user_agent')
->maxLength(1023),
Forms\Components\TextInput::make('tags')
->maxLength(255),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('user.name'),
Tables\Columns\TextColumn::make('event'),
Tables\Columns\TextColumn::make('auditable_type'),
Tables\Columns\TextColumn::make('auditable_id'),
IconColumn::make('was_command')
->getStateUsing(fn (Audit $record) => Str::startsWith($record->url, 'artisan '))
->boolean(),
Tables\Columns\TextColumn::make('created_at')
->sortable()
->dateTime(),
Tables\Columns\TextColumn::make('updated_at')
->sortable()
->dateTime(),
])
->filters([
//
])
->actions([
Tables\Actions\ViewAction::make(),
])
->bulkActions([
])
->defaultSort('created_at', 'desc');
}
public static function getRelations(): array
{
return [
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListAudits::route('/'),
'create' => Pages\CreateAudit::route('/create'),
'view' => Pages\ViewAudit::route('/{record}'),
];
}
}
================================================
FILE: app/Filament/Resources/ClientResource/Pages/CreateClient.php
================================================
<?php
declare(strict_types=1);
namespace App\Filament\Resources\ClientResource\Pages;
use App\Filament\Resources\ClientResource;
use Filament\Resources\Pages\CreateRecord;
class CreateClient extends CreateRecord
{
protected static string $resource = ClientResource::class;
}
================================================
FILE: app/Filament/Resources/ClientResource/Pages/EditClient.php
================================================
<?php
declare(strict_types=1);
namespace App\Filament\Resources\ClientResource\Pages;
use App\Filament\Resources\ClientResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditClient extends EditRecord
{
protected static string $resource = ClientResource::class;
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make()
->icon('heroicon-m-trash'),
];
}
}
================================================
FILE: app/Filament/Resources/ClientResource/Pages/ListClients.php
================================================
<?php
declare(strict_types=1);
namespace App\Filament\Resources\ClientResource\Pages;
use App\Filament\Resources\ClientResource;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
class ListClients extends ListRecords
{
protected static string $resource = ClientResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make()
->icon('heroicon-s-plus'),
];
}
}
================================================
FILE: app/Filament/Resources/ClientResource.php
================================================
<?php
declare(strict_types=1);
namespace App\Filament\Resources;
use App\Filament\Resources\ClientResource\Pages;
use App\Models\Client;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
class ClientResource extends Resource
{
protected static ?string $model = Client::class;
protected static ?string $navigationIcon = 'heroicon-o-briefcase';
protected static ?string $navigationGroup = 'Timetracking';
protected static ?int $navigationSort = 4;
public static function form(Form $form): Form
{
return $form
->schema([
TextInput::make('name')
->label('Name')
->required(),
Select::make('organization_id')
->relationship(name: 'organization', titleAttribute: 'name')
->label('Organization')
->searchable(['name'])
->required(),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('name')
->label('Name')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('organization.name')
->sortable()
->label('Organization'),
Tables\Columns\TextColumn::make('created_at')
->label('Created at')
->sortable(),
Tables\Columns\TextColumn::make('updated_at')
->label('Updated at')
->sortable(),
])
->defaultSort('created_at', 'desc')
->filters([
SelectFilter::make('organization')
->label('Organization')
->relationship('organization', 'name')
->searchable(),
SelectFilter::make('organization_id')
->label('Organization ID')
->relationship('organization', 'id')
->searchable(),
])
->actions([
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListClients::route('/'),
'create' => Pages\CreateClient::route('/create'),
'edit' => Pages\EditClient::route('/{record}/edit'),
];
}
}
================================================
FILE: app/Filament/Resources/FailedJobResource/Pages/ListFailedJobs.php
================================================
<?php
declare(strict_types=1);
namespace App\Filament\Resources\FailedJobResource\Pages;
use App\Filament\Resources\FailedJobResource;
use App\Models\FailedJob;
use Filament\Actions\Action;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\ListRecords;
use Illuminate\Support\Facades\Artisan;
class ListFailedJobs extends ListRecords
{
protected static string $resource = FailedJobResource::class;
public function getHeaderActions(): array
{
return [
Action::make('retry_all')
->icon('heroicon-o-arrow-path')
->label('Retry all')
->requiresConfirmation()
->action(function (): void {
Artisan::call('queue:retry all');
Notification::make()
->title('All failed jobs have been pushed back onto the queue.')
->success()
->send();
}),
Action::make('delete_all')
->icon('heroicon-o-trash')
->label('Delete all')
->requiresConfirmation()
->color('danger')
->action(function (): void {
FailedJob::truncate();
Notification::make()
->title('All failed jobs have been removed.')
->success()
->send();
}),
];
}
}
================================================
FILE: app/Filament/Resources/FailedJobResource/Pages/ViewFailedJobs.php
================================================
<?php
declare(strict_types=1);
namespace App\Filament\Resources\FailedJobResource\Pages;
use App\Filament\Resources\FailedJobResource;
use Filament\Resources\Pages\ViewRecord;
class ViewFailedJobs extends ViewRecord
{
protected static string $resource = FailedJobResource::class;
}
================================================
FILE: app/Filament/Resources/FailedJobResource.php
================================================
<?php
declare(strict_types=1);
namespace App\Filament\Resources;
use App\Filament\Resources\FailedJobResource\Pages\ListFailedJobs;
use App\Filament\Resources\FailedJobResource\Pages\ViewFailedJobs;
use App\Models\FailedJob;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Notifications\Notification;
use Filament\Resources\Resource;
use Filament\Tables\Actions\Action;
use Filament\Tables\Actions\BulkAction;
use Filament\Tables\Actions\DeleteAction;
use Filament\Tables\Actions\DeleteBulkAction;
use Filament\Tables\Actions\ViewAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Artisan;
use Novadaemon\FilamentPrettyJson\Form\PrettyJsonField;
/**
* @source https://gitlab.com/amvisor/filament-failed-jobs
*/
class FailedJobResource extends Resource
{
protected static ?string $model = FailedJob::class;
protected static ?string $navigationIcon = 'heroicon-o-exclamation-circle';
protected static ?string $navigationGroup = 'System';
public static function getNavigationBadge(): ?string
{
return (string) FailedJob::query()->count();
}
public static function form(Form $form): Form
{
return $form
->schema([
TextInput::make('uuid')->disabled()->columnSpan(4),
TextInput::make('failed_at')->disabled(),
TextInput::make('id')->disabled(),
TextInput::make('connection')->disabled(),
TextInput::make('queue')->disabled(),
// make text a little bit smaller because often a complete Stack Trace is shown:
TextArea::make('exception')->disabled()->columnSpan(4)->extraInputAttributes(['style' => 'font-size: 80%;']),
PrettyJsonField::make('payload')->disabled()->columnSpan(4),
])->columns(4);
}
public static function table(Table $table): Table
{
return $table
->defaultSort('id', 'desc')
->columns([
TextColumn::make('id')->sortable()->searchable()->toggleable(),
TextColumn::make('failed_at')->sortable()->searchable(false)->toggleable(),
TextColumn::make('exception')
->sortable()
->searchable()
->toggleable()
->wrap()
->limit(200)
->tooltip(fn (FailedJob $record) => "{$record->failed_at} UUID: {$record->uuid}; Connection: {$record->connection}; Queue: {$record->queue};"),
TextColumn::make('uuid')->sortable()->searchable()->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('connection')->sortable()->searchable()->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('queue')->sortable()->searchable()->toggleable(isToggledHiddenByDefault: true),
])
->filters([])
->bulkActions([
BulkAction::make('retry')
->icon('heroicon-o-arrow-path')
->label('Retry selected')
->requiresConfirmation()
->action(function (Collection $records): void {
/** @var FailedJob $record */
foreach ($records as $record) {
Artisan::call("queue:retry {$record->uuid}");
}
Notification::make()
->title("{$records->count()} jobs have been pushed back onto the queue.")
->success()
->send();
}),
DeleteBulkAction::make(),
])
->actions([
DeleteAction::make(),
ViewAction::make(),
Action::make('retry')
->icon('heroicon-o-arrow-path')
->label('Retry')
->requiresConfirmation()
->action(function (FailedJob $record): void {
Artisan::call("queue:retry {$record->uuid}");
Notification::make()
->title("The job with uuid '{$record->uuid}' has been pushed back onto the queue.")
->success()
->send();
}),
]);
}
public static function getPages(): array
{
return [
'index' => ListFailedJobs::route('/'),
'view' => ViewFailedJobs::route('/{record}'),
];
}
}
================================================
FILE: app/Filament/Resources/OrganizationInvitationResource/Pages/EditOrganizationInvitation.php
================================================
<?php
declare(strict_types=1);
namespace App\Filament\Resources\OrganizationInvitationResource\Pages;
use App\Filament\Resources\OrganizationInvitationResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
class EditOrganizationInvitation extends EditRecord
{
protected static string $resource = OrganizationInvitationResource::class;
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make()
->icon('heroicon-m-trash'),
];
}
}
================================================
FILE: app/Filament/Resources/OrganizationInvitationResource/Pages/ListOrganizationInvitations.php
================================================
<?php
declare(strict_types=1);
namespace App\Filament\Resources\OrganizationInvitationResource\Pages;
use App\Filament\Resources\OrganizationInvitationResource;
use Filament\Resources\Pages\ListRecords;
class ListOrganizationInvitations extends ListRecords
{
protected static string $resource = OrganizationInvitationResource::class;
protected function getHeaderActions(): array
{
return [
];
}
}
================================================
FILE: app/Filament/Resources/OrganizationInvitationResource/Pages/ViewOrganizationInvitation.php
================================================
<?php
declare(strict_types=1);
namespace App\Filament\Resources\OrganizationInvitationResource\Pages;
use App\Filament\Resources\OrganizationInvitationResource;
use Filament\Actions\EditAction;
use Filament\Resources\Pages\ViewRecord;
class ViewOrganizationInvitation extends ViewRecord
{
protected static string $resource = OrganizationInvitationResource::class;
protected function getHeaderActions(): array
{
return [
EditAction::make('edit')
->icon('heroicon-s-pencil'),
];
}
}
================================================
FILE: app/Filament/Resources/OrganizationInvitationResource.php
================================================
<?php
declare(strict_types=1);
namespace App\Filament\Resources;
use App\Enums\Role;
use App\Filament\Resources\OrganizationInvitationResource\Pages;
use App\Models\OrganizationInvitation;
use App\Service\OrganizationInvitationService;
use Filament\Forms;
use Filament\Forms\Components\Select;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Support\Collection;
class OrganizationInvitationResource extends Resource
{
protected static ?string $model = OrganizationInvitation::class;
protected static ?string $label = 'Invitations';
protected static ?string $navigationIcon = 'heroicon-o-user-plus';
protected static ?string $navigationGroup = 'Users';
protected static ?int $navigationSort = 9;
public static function form(Form $form): Form
{
return $form
->columns(1)
->schema([
Forms\Components\TextInput::make('email')
->label('Email')
->disabledOn(['edit'])
->required(),
Select::make('role')
->options(Role::class),
Forms\Components\Select::make('organization_id')
->label('Organization')
->relationship(name: 'organization', titleAttribute: 'name')
->searchable(['name'])
->disabledOn(['edit'])
->required(),
Forms\Components\DateTimePicker::make('created_at')
->label('Created At')
->hiddenOn(['create'])
->disabled(),
Forms\Components\DateTimePicker::make('updated_at')
->label('Updated At')
->hiddenOn(['create'])
->disabled(),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('organization.name')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('email')
->sortable(),
Tables\Columns\TextColumn::make('role'),
Tables\Columns\TextColumn::make('created_at')
->label('Created At')
->dateTime()
->sortable(),
Tables\Columns\TextColumn::make('updated_at')
->label('Updated At')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->defaultSort('created_at', 'desc')
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\BulkAction::make('resend')
->label('Resend')
->action(function (Collection $records): void {
foreach ($records as $organizationInvite) {
app(OrganizationInvitationService::class)->resend($organizationInvite);
}
}),
]),
]);
}
public static function getRelations(): array
{
return [
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListOrganizationInvitations::route('/'),
'edit' => Pages\EditOrganizationInvitation::route('/{record}/edit'),
'view' => Pages\ViewOrganizationInvitation::route('/{record}'),
];
}
}
================================================
FILE: app/Filament/Resources/OrganizationResource/Actions/DeleteOrganization.php
================================================
<?php
declare(strict_types=1);
namespace App\Filament\Resources\OrganizationResource\Actions;
use App\Exceptions\Api\ApiException;
use App\Models\Organization;
use App\Service\DeletionService;
use Filament\Actions\DeleteAction;
use Throwable;
class DeleteOrganization extends DeleteAction
{
protected function setUp(): void
{
parent::setUp();
$this->icon('heroicon-m-trash');
$this->action(function (): void {
$result = $this->process(function (Organization $record): bool {
try {
$deletionService = app(DeletionService::class);
$deletionService->deleteOrganization($record);
return true;
} catch (ApiException $exception) {
$this->failureNotificationTitle($exception->getTranslatedMessage());
report($exception);
} catch (Throwable $exception) {
$this->failureNotificationTitle(__('exceptions.unknown_error_in_admin_panel'));
report($exception);
}
return false;
});
if (! $result) {
$this->failure();
return;
}
$this->success();
});
}
}
================================================
FILE: app/Filament/Resources/OrganizationResource/Pages/CreateOrganization.php
================================================
<?php
declare(strict_types=1);
namespace App\Filament\Resources\OrganizationResource\Pages;
use App\Enums\Role;
use App\Filament\Resources\OrganizationResource;
use App\Models\Organization;
use Filament\Resources\Pages\CreateRecord;
class CreateOrganization extends CreateRecord
{
protected static string $resource = OrganizationResource::class;
protected function mutateFormDataBeforeCreate(array $data): array
{
$data['personal_team'] = false;
return $data;
}
protected function afterCreate(): void
{
/** @var Organization $organization */
$organization = $this->record;
$user = $organization->owner;
$organization->users()->attach(
$user, [
'role' => Role::Owner->value,
]
);
}
}
================================================
FILE: app/Filament/Resources/OrganizationResource/Pages/EditOrganization.php
================================================
<?php
declare(strict_types=1);
namespace App\Filament\Resources\OrganizationResource\Pages;
use App\Filament\Resources\OrganizationResource;
use Filament\Resources\Pages\EditRecord;
class EditOrganization extends EditRecord
{
protected static string $resource = OrganizationResource::class;
protected function getHeaderActions(): array
{
return [
OrganizationResource\Actions\DeleteOrganization::make(),
];
}
}
================================================
FILE: app/Filament/Resources/OrganizationResource/Pages/ListOrganizations.php
==========================
gitextract_ryuvl2mb/ ├── .editorconfig ├── .gitattributes ├── .github/ │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ ├── 1_bug_report.yml │ │ └── config.yml │ ├── PULL_REQUEST_TEMPLATE.md │ ├── dependabot.yml │ └── workflows/ │ ├── build-onpremise.yml │ ├── build-private.yml │ ├── build-public.yml │ ├── generate-api-docs.yml │ ├── npm-build.yml │ ├── npm-format-check.yml │ ├── npm-lint.yml │ ├── npm-publish-api.yml │ ├── npm-publish-ui.yml │ ├── npm-typecheck.yml │ ├── phpstan.yml │ ├── phpunit.yml │ ├── pint.yml │ └── playwright.yml ├── .gitignore ├── .prettierignore ├── .prettierrc.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── SECURITY.md ├── app/ │ ├── Actions/ │ │ ├── Fortify/ │ │ │ ├── CreateNewUser.php │ │ │ ├── PasswordValidationRules.php │ │ │ ├── ResetUserPassword.php │ │ │ ├── UpdateUserPassword.php │ │ │ └── UpdateUserProfileInformation.php │ │ └── Jetstream/ │ │ ├── AddOrganizationMember.php │ │ ├── CreateOrganization.php │ │ ├── DeleteOrganization.php │ │ ├── DeleteUser.php │ │ ├── InviteOrganizationMember.php │ │ ├── RemoveOrganizationMember.php │ │ ├── UpdateMemberRole.php │ │ ├── UpdateOrganization.php │ │ └── ValidateOrganizationDeletion.php │ ├── Console/ │ │ ├── Commands/ │ │ │ ├── Admin/ │ │ │ │ ├── OrganizationDeleteCommand.php │ │ │ │ ├── UserCreateCommand.php │ │ │ │ └── UserVerifyCommand.php │ │ │ ├── Auth/ │ │ │ │ └── AuthSendReminderForExpiringApiTokensCommand.php │ │ │ ├── Correction/ │ │ │ │ └── CorrectionPlaceholderMembersCommand.php │ │ │ ├── Report/ │ │ │ │ └── ReportSetExpiredToPrivateCommand.php │ │ │ ├── SelfHost/ │ │ │ │ ├── SelfHostCheckForUpdateCommand.php │ │ │ │ ├── SelfHostDatabaseConsistency.php │ │ │ │ ├── SelfHostGenerateKeysCommand.php │ │ │ │ └── SelfHostTelemetryCommand.php │ │ │ ├── Test/ │ │ │ │ ├── TestEmailCommand.php │ │ │ │ ├── TestJobCommand.php │ │ │ │ └── TestOutputCommand.php │ │ │ └── TimeEntry/ │ │ │ └── TimeEntrySendStillRunningMailsCommand.php │ │ └── Kernel.php │ ├── Enums/ │ │ ├── CurrencyFormat.php │ │ ├── DateFormat.php │ │ ├── ExportFormat.php │ │ ├── IntervalFormat.php │ │ ├── NumberFormat.php │ │ ├── Role.php │ │ ├── TimeEntryAggregationType.php │ │ ├── TimeEntryAggregationTypeInterval.php │ │ ├── TimeEntryRoundingType.php │ │ ├── TimeFormat.php │ │ └── Weekday.php │ ├── Events/ │ │ ├── AfterCreateOrganization.php │ │ ├── BeforeOrganizationDeletion.php │ │ ├── DatabaseSeederAfterSeed.php │ │ ├── DatabaseSeederBeforeDelete.php │ │ ├── MemberMadeToPlaceholder.php │ │ ├── MemberRemoved.php │ │ └── NewsletterRegistered.php │ ├── Exceptions/ │ │ ├── Api/ │ │ │ ├── ApiException.php │ │ │ ├── CanNotDeleteUserWhoIsOwnerOfOrganizationWithMultipleMembers.php │ │ │ ├── CanNotRemoveOwnerFromOrganization.php │ │ │ ├── ChangingRoleOfPlaceholderIsNotAllowed.php │ │ │ ├── ChangingRoleToPlaceholderIsNotAllowed.php │ │ │ ├── EntityStillInUseApiException.php │ │ │ ├── FeatureIsNotAvailableInFreePlanApiException.php │ │ │ ├── InactiveUserCanNotBeUsedApiException.php │ │ │ ├── InvitationForTheEmailAlreadyExistsApiException.php │ │ │ ├── OnlyOwnerCanChangeOwnership.php │ │ │ ├── OnlyPlaceholdersCanBeMergedIntoAnotherMember.php │ │ │ ├── OrganizationHasNoSubscriptionButMultipleMembersException.php │ │ │ ├── OrganizationNeedsAtLeastOneOwner.php │ │ │ ├── OverlappingTimeEntryApiException.php │ │ │ ├── PdfRendererIsNotConfiguredException.php │ │ │ ├── PersonalAccessClientIsNotConfiguredException.php │ │ │ ├── ThisPlaceholderCanNotBeInvitedUseTheMergeToolInsteadException.php │ │ │ ├── TimeEntryCanNotBeRestartedApiException.php │ │ │ ├── TimeEntryStillRunningApiException.php │ │ │ ├── UserIsAlreadyMemberOfOrganizationApiException.php │ │ │ ├── UserIsAlreadyMemberOfProjectApiException.php │ │ │ └── UserNotPlaceholderApiException.php │ │ ├── Handler.php │ │ └── MovedToApiException.php │ ├── Extensions/ │ │ ├── Auditing/ │ │ │ └── Resolvers/ │ │ │ └── CustomIpAddressResolver.php │ │ ├── Fortify/ │ │ │ ├── CustomLoginResponse.php │ │ │ └── CustomTwoFactorLoginResponse.php │ │ └── Scramble/ │ │ ├── ApiExceptionTypeToSchema.php │ │ └── PaginatedResourceCollectionTypeToSchema.php │ ├── Filament/ │ │ ├── Resources/ │ │ │ ├── AuditResource/ │ │ │ │ └── Pages/ │ │ │ │ ├── CreateAudit.php │ │ │ │ ├── ListAudits.php │ │ │ │ └── ViewAudit.php │ │ │ ├── AuditResource.php │ │ │ ├── ClientResource/ │ │ │ │ └── Pages/ │ │ │ │ ├── CreateClient.php │ │ │ │ ├── EditClient.php │ │ │ │ └── ListClients.php │ │ │ ├── ClientResource.php │ │ │ ├── FailedJobResource/ │ │ │ │ └── Pages/ │ │ │ │ ├── ListFailedJobs.php │ │ │ │ └── ViewFailedJobs.php │ │ │ ├── FailedJobResource.php │ │ │ ├── OrganizationInvitationResource/ │ │ │ │ └── Pages/ │ │ │ │ ├── EditOrganizationInvitation.php │ │ │ │ ├── ListOrganizationInvitations.php │ │ │ │ └── ViewOrganizationInvitation.php │ │ │ ├── OrganizationInvitationResource.php │ │ │ ├── OrganizationResource/ │ │ │ │ ├── Actions/ │ │ │ │ │ └── DeleteOrganization.php │ │ │ │ ├── Pages/ │ │ │ │ │ ├── CreateOrganization.php │ │ │ │ │ ├── EditOrganization.php │ │ │ │ │ ├── ListOrganizations.php │ │ │ │ │ └── ViewOrganization.php │ │ │ │ └── RelationManagers/ │ │ │ │ ├── InvitationsRelationManager.php │ │ │ │ └── UsersRelationManager.php │ │ │ ├── OrganizationResource.php │ │ │ ├── ProjectMemberResource/ │ │ │ │ └── Pages/ │ │ │ │ ├── CreateProjectMember.php │ │ │ │ ├── EditProjectMember.php │ │ │ │ ├── ListProjectMembers.php │ │ │ │ └── ViewProjectMembers.php │ │ │ ├── ProjectMemberResource.php │ │ │ ├── ProjectResource/ │ │ │ │ ├── Pages/ │ │ │ │ │ ├── CreateProject.php │ │ │ │ │ ├── EditProject.php │ │ │ │ │ └── ListProjects.php │ │ │ │ └── RelationManagers/ │ │ │ │ └── ProjectMembersRelationManager.php │ │ │ ├── ProjectResource.php │ │ │ ├── ReportResource/ │ │ │ │ └── Pages/ │ │ │ │ ├── EditReport.php │ │ │ │ ├── ListReports.php │ │ │ │ └── ViewReport.php │ │ │ ├── ReportResource.php │ │ │ ├── TagResource/ │ │ │ │ └── Pages/ │ │ │ │ ├── CreateTag.php │ │ │ │ ├── EditTag.php │ │ │ │ └── ListTags.php │ │ │ ├── TagResource.php │ │ │ ├── TaskResource/ │ │ │ │ └── Pages/ │ │ │ │ ├── CreateTask.php │ │ │ │ ├── EditTask.php │ │ │ │ └── ListTasks.php │ │ │ ├── TaskResource.php │ │ │ ├── TimeEntryResource/ │ │ │ │ └── Pages/ │ │ │ │ ├── CreateTimeEntry.php │ │ │ │ ├── EditTimeEntry.php │ │ │ │ └── ListTimeEntries.php │ │ │ ├── TimeEntryResource.php │ │ │ ├── TokenResource/ │ │ │ │ └── Pages/ │ │ │ │ ├── ListTokens.php │ │ │ │ └── ViewToken.php │ │ │ ├── TokenResource.php │ │ │ ├── UserResource/ │ │ │ │ ├── Actions/ │ │ │ │ │ └── DeleteUser.php │ │ │ │ ├── Pages/ │ │ │ │ │ ├── CreateUser.php │ │ │ │ │ ├── EditUser.php │ │ │ │ │ ├── ListUsers.php │ │ │ │ │ └── ViewUser.php │ │ │ │ └── RelationManagers/ │ │ │ │ ├── OrganizationsRelationManager.php │ │ │ │ └── OwnedOrganizationsRelationManager.php │ │ │ └── UserResource.php │ │ └── Widgets/ │ │ ├── ActiveUserOverview.php │ │ ├── ServerOverview.php │ │ ├── TimeEntriesCreated.php │ │ ├── TimeEntriesImported.php │ │ └── UserRegistrations.php │ ├── Http/ │ │ ├── Controllers/ │ │ │ ├── Api/ │ │ │ │ └── V1/ │ │ │ │ ├── ApiTokenController.php │ │ │ │ ├── ChartController.php │ │ │ │ ├── ClientController.php │ │ │ │ ├── Controller.php │ │ │ │ ├── CurrencyController.php │ │ │ │ ├── ExportController.php │ │ │ │ ├── ImportController.php │ │ │ │ ├── InvitationController.php │ │ │ │ ├── MemberController.php │ │ │ │ ├── OrganizationController.php │ │ │ │ ├── ProjectController.php │ │ │ │ ├── ProjectMemberController.php │ │ │ │ ├── Public/ │ │ │ │ │ └── ReportController.php │ │ │ │ ├── ReportController.php │ │ │ │ ├── TagController.php │ │ │ │ ├── TaskController.php │ │ │ │ ├── TimeEntryController.php │ │ │ │ ├── UserController.php │ │ │ │ ├── UserMembershipController.php │ │ │ │ └── UserTimeEntryController.php │ │ │ ├── Controller.php │ │ │ └── Web/ │ │ │ ├── Controller.php │ │ │ ├── DashboardController.php │ │ │ ├── HealthCheckController.php │ │ │ └── HomeController.php │ │ ├── Kernel.php │ │ ├── Middleware/ │ │ │ ├── Authenticate.php │ │ │ ├── CheckOrganizationBlocked.php │ │ │ ├── EncryptCookies.php │ │ │ ├── EnsureEmailIsVerified.php │ │ │ ├── ForceHttps.php │ │ │ ├── ForceJsonResponse.php │ │ │ ├── HandleInertiaRequests.php │ │ │ ├── PreventRequestsDuringMaintenance.php │ │ │ ├── RedirectIfAuthenticated.php │ │ │ ├── ShareInertiaData.php │ │ │ ├── TrimStrings.php │ │ │ ├── TrustProxies.php │ │ │ ├── ValidateSignature.php │ │ │ └── VerifyCsrfToken.php │ │ ├── Requests/ │ │ │ └── V1/ │ │ │ ├── ApiToken/ │ │ │ │ └── ApiTokenStoreRequest.php │ │ │ ├── BaseFormRequest.php │ │ │ ├── Client/ │ │ │ │ ├── ClientIndexRequest.php │ │ │ │ ├── ClientStoreRequest.php │ │ │ │ └── ClientUpdateRequest.php │ │ │ ├── Import/ │ │ │ │ └── ImportRequest.php │ │ │ ├── Invitation/ │ │ │ │ ├── InvitationIndexRequest.php │ │ │ │ └── InvitationStoreRequest.php │ │ │ ├── Member/ │ │ │ │ ├── MemberDestroyRequest.php │ │ │ │ ├── MemberIndexRequest.php │ │ │ │ ├── MemberMergeIntoRequest.php │ │ │ │ └── MemberUpdateRequest.php │ │ │ ├── Organization/ │ │ │ │ └── OrganizationUpdateRequest.php │ │ │ ├── Project/ │ │ │ │ ├── ProjectIndexRequest.php │ │ │ │ ├── ProjectStoreRequest.php │ │ │ │ └── ProjectUpdateRequest.php │ │ │ ├── ProjectMember/ │ │ │ │ ├── ProjectMemberIndexRequest.php │ │ │ │ ├── ProjectMemberStoreRequest.php │ │ │ │ └── ProjectMemberUpdateRequest.php │ │ │ ├── Report/ │ │ │ │ ├── ReportIndexRequest.php │ │ │ │ ├── ReportStoreRequest.php │ │ │ │ └── ReportUpdateRequest.php │ │ │ ├── Tag/ │ │ │ │ ├── TagIndexRequest.php │ │ │ │ ├── TagStoreRequest.php │ │ │ │ └── TagUpdateRequest.php │ │ │ ├── Task/ │ │ │ │ ├── TaskIndexRequest.php │ │ │ │ ├── TaskStoreRequest.php │ │ │ │ └── TaskUpdateRequest.php │ │ │ └── TimeEntry/ │ │ │ ├── TimeEntryAggregateExportRequest.php │ │ │ ├── TimeEntryAggregateRequest.php │ │ │ ├── TimeEntryDestroyMultipleRequest.php │ │ │ ├── TimeEntryIndexExportRequest.php │ │ │ ├── TimeEntryIndexRequest.php │ │ │ ├── TimeEntryStoreRequest.php │ │ │ ├── TimeEntryUpdateMultipleRequest.php │ │ │ └── TimeEntryUpdateRequest.php │ │ └── Resources/ │ │ ├── PaginatedResourceCollection.php │ │ └── V1/ │ │ ├── ApiToken/ │ │ │ ├── ApiTokenCollection.php │ │ │ ├── ApiTokenResource.php │ │ │ └── ApiTokenWithAccessTokenResource.php │ │ ├── BaseResource.php │ │ ├── Client/ │ │ │ ├── ClientCollection.php │ │ │ └── ClientResource.php │ │ ├── Invitation/ │ │ │ ├── InvitationCollection.php │ │ │ └── InvitationResource.php │ │ ├── Member/ │ │ │ ├── MemberCollection.php │ │ │ ├── MemberResource.php │ │ │ ├── PersonalMembershipCollection.php │ │ │ └── PersonalMembershipResource.php │ │ ├── Organization/ │ │ │ └── OrganizationResource.php │ │ ├── Project/ │ │ │ ├── ProjectCollection.php │ │ │ └── ProjectResource.php │ │ ├── ProjectMember/ │ │ │ ├── ProjectMemberCollection.php │ │ │ └── ProjectMemberResource.php │ │ ├── Report/ │ │ │ ├── DetailedReportResource.php │ │ │ ├── DetailedWithDataReportResource.php │ │ │ ├── ReportCollection.php │ │ │ └── ReportResource.php │ │ ├── Tag/ │ │ │ ├── TagCollection.php │ │ │ └── TagResource.php │ │ ├── Task/ │ │ │ ├── TaskCollection.php │ │ │ └── TaskResource.php │ │ ├── TimeEntry/ │ │ │ ├── TimeEntryCollection.php │ │ │ └── TimeEntryResource.php │ │ └── User/ │ │ └── UserResource.php │ ├── Jobs/ │ │ ├── RecalculateSpentTimeForProject.php │ │ ├── RecalculateSpentTimeForTask.php │ │ └── Test/ │ │ └── TestJob.php │ ├── Listeners/ │ │ └── RemovePlaceholder.php │ ├── Mail/ │ │ ├── AuthApiTokenExpirationReminderMail.php │ │ ├── AuthApiTokenExpiredMail.php │ │ ├── OrganizationInvitationMail.php │ │ └── TimeEntryStillRunningMail.php │ ├── Models/ │ │ ├── Audit.php │ │ ├── Client.php │ │ ├── Concerns/ │ │ │ ├── CustomAuditable.php │ │ │ └── HasUuids.php │ │ ├── FailedJob.php │ │ ├── Member.php │ │ ├── Organization.php │ │ ├── OrganizationInvitation.php │ │ ├── Passport/ │ │ │ ├── AuthCode.php │ │ │ ├── Client.php │ │ │ ├── RefreshToken.php │ │ │ └── Token.php │ │ ├── Project.php │ │ ├── ProjectMember.php │ │ ├── Report.php │ │ ├── Tag.php │ │ ├── Task.php │ │ ├── TimeEntry.php │ │ └── User.php │ ├── Policies/ │ │ └── OrganizationPolicy.php │ ├── Providers/ │ │ ├── AppServiceProvider.php │ │ ├── AuthServiceProvider.php │ │ ├── EventServiceProvider.php │ │ ├── Filament/ │ │ │ └── AdminPanelProvider.php │ │ ├── FortifyServiceProvider.php │ │ ├── JetstreamServiceProvider.php │ │ ├── RouteServiceProvider.php │ │ └── TelescopeServiceProvider.php │ ├── Rules/ │ │ ├── ColorRule.php │ │ └── CurrencyRule.php │ └── Service/ │ ├── ApiService.php │ ├── BillableRateService.php │ ├── BillingContract.php │ ├── ColorService.php │ ├── CurrencyService.php │ ├── DashboardService.php │ ├── DeletionService.php │ ├── Dto/ │ │ └── ReportPropertiesDto.php │ ├── Export/ │ │ ├── ExportException.php │ │ └── ExportService.php │ ├── Import/ │ │ ├── ImportDatabaseHelper.php │ │ ├── ImportService.php │ │ └── Importers/ │ │ ├── ClockifyProjectsImporter.php │ │ ├── ClockifyTimeEntriesImporter.php │ │ ├── DefaultImporter.php │ │ ├── GenericProjectsImporter.php │ │ ├── GenericTimeEntriesImporter.php │ │ ├── HarvestClientsImporter.php │ │ ├── HarvestProjectsImporter.php │ │ ├── HarvestTimeEntriesImporter.php │ │ ├── ImportException.php │ │ ├── ImporterContract.php │ │ ├── ImporterProvider.php │ │ ├── ReportDto.php │ │ ├── SolidtimeImporter.php │ │ ├── TogglDataImporter.php │ │ └── TogglTimeEntriesImporter.php │ ├── IntervalService.php │ ├── InvitationService.php │ ├── IpLookup/ │ │ ├── IpLookupResponseDto.php │ │ ├── IpLookupServiceContract.php │ │ └── NoIpLookupService.php │ ├── LocalizationService.php │ ├── MemberService.php │ ├── OrganizationInvitationService.php │ ├── OrganizationService.php │ ├── PermissionStore.php │ ├── ReportExport/ │ │ ├── CsvExport.php │ │ ├── TimeEntriesDetailedCsvExport.php │ │ ├── TimeEntriesDetailedExport.php │ │ └── TimeEntriesReportExport.php │ ├── ReportService.php │ ├── TimeEntryAggregationService.php │ ├── TimeEntryFilter.php │ ├── TimeEntryService.php │ ├── TimezoneService.php │ └── UserService.php ├── artisan ├── bootstrap/ │ ├── app.php │ └── cache/ │ └── .gitignore ├── components.json ├── composer.json ├── config/ │ ├── app.php │ ├── audit.php │ ├── auth.php │ ├── broadcasting.php │ ├── cache.php │ ├── cors.php │ ├── database.php │ ├── excel.php │ ├── filament.php │ ├── filesystems.php │ ├── fortify.php │ ├── hashing.php │ ├── jetstream.php │ ├── logging.php │ ├── mail.php │ ├── modules.php │ ├── octane.php │ ├── passport.php │ ├── queue.php │ ├── scheduling.php │ ├── scramble.php │ ├── services.php │ ├── session.php │ ├── telescope.php │ ├── trustedproxy.php │ └── view.php ├── database/ │ ├── .gitignore │ ├── factories/ │ │ ├── AuditFactory.php │ │ ├── ClientFactory.php │ │ ├── FailedJobFactory.php │ │ ├── MemberFactory.php │ │ ├── OrganizationFactory.php │ │ ├── OrganizationInvitationFactory.php │ │ ├── Passport/ │ │ │ ├── ClientFactory.php │ │ │ └── TokenFactory.php │ │ ├── ProjectFactory.php │ │ ├── ProjectMemberFactory.php │ │ ├── ReportFactory.php │ │ ├── TagFactory.php │ │ ├── TaskFactory.php │ │ ├── TimeEntryFactory.php │ │ └── UserFactory.php │ ├── migrations/ │ │ ├── 2014_10_12_000000_create_users_table.php │ │ ├── 2014_10_12_100000_create_password_reset_tokens_table.php │ │ ├── 2014_10_12_200000_add_two_factor_columns_to_users_table.php │ │ ├── 2016_06_01_000001_create_oauth_auth_codes_table.php │ │ ├── 2016_06_01_000002_create_oauth_access_tokens_table.php │ │ ├── 2016_06_01_000003_create_oauth_refresh_tokens_table.php │ │ ├── 2016_06_01_000004_create_oauth_clients_table.php │ │ ├── 2016_06_01_000005_create_oauth_personal_access_clients_table.php │ │ ├── 2018_08_08_100000_create_telescope_entries_table.php │ │ ├── 2019_08_19_000000_create_failed_jobs_table.php │ │ ├── 2019_12_14_000001_create_personal_access_tokens_table.php │ │ ├── 2020_05_21_100000_create_organizations_table.php │ │ ├── 2020_05_21_200000_create_organization_user_table.php │ │ ├── 2020_05_21_300000_create_organization_invitations_table.php │ │ ├── 2024_01_16_161030_create_sessions_table.php │ │ ├── 2024_01_20_110218_create_clients_table.php │ │ ├── 2024_01_20_110439_create_projects_table.php │ │ ├── 2024_01_20_110444_create_tasks_table.php │ │ ├── 2024_01_20_110452_create_tags_table.php │ │ ├── 2024_01_20_110837_create_time_entries_table.php │ │ ├── 2024_03_26_171253_create_project_members_table.php │ │ ├── 2024_04_11_150130_create_jobs_table.php │ │ ├── 2024_04_12_095010_create_cache_table.php │ │ ├── 2024_05_07_134711_move_from_user_id_to_member_id_in_project_members_table.php │ │ ├── 2024_05_07_141842_move_from_user_id_to_member_id_in_time_entries_table.php │ │ ├── 2024_05_13_171020_rename_table_organization_user_to_members.php │ │ ├── 2024_05_22_151226_add_client_id_to_time_entries_table.php │ │ ├── 2024_05_30_175801_add_is_billable_column_to_projects_table.php │ │ ├── 2024_05_30_175825_add_is_imported_column_to_time_entries_table.php │ │ ├── 2024_06_01_000001_create_oauth_device_codes_table.php │ │ ├── 2024_06_07_113443_change_member_id_foreign_keys_to_restrict_on_delete.php │ │ ├── 2024_06_10_161831_reset_billable_rates_with_zero_as_value.php │ │ ├── 2024_06_21_122754_add_is_archived_columns_to_projects_and_clients_table.php │ │ ├── 2024_06_24_114433_add_done_at_to_tasks_table.php │ │ ├── 2024_07_02_134307_add_estimated_time_to_projects_and_tasks_table.php │ │ ├── 2024_07_03_145445_change_data_type_of_id_column_in_failed_jobs_table.php │ │ ├── 2024_07_18_080906_add_still_active_email_sent_at_to_time_entries_table.php │ │ ├── 2024_08_01_104840_create_reports_table.php │ │ ├── 2024_09_02_094105_create_audits_table.php │ │ ├── 2024_09_18_120203_add_spent_time_to_projects_and_tasks_table.php │ │ ├── 2024_10_01_143608_add_employees_can_see_billable_rates_to_organizations_table.php │ │ ├── 2024_11_04_164807_add_foreign_key_to_organizations_and_members_table.php │ │ ├── 2024_11_04_170614_add_foreign_keys_to_oauth_tables.php │ │ ├── 2025_04_03_101827_add_localization_columns_to_organizations_table.php │ │ ├── 2025_04_25_202047_change_data_type_for_spent_time_columns.php │ │ ├── 2025_05_06_152804_fix_typos_in_organizations_table_format_columns.php │ │ ├── 2025_05_16_075757_add_foreign_key_for_current_team_id_in_users_table.php │ │ ├── 2025_06_30_095942_remove_oauth_personal_access_clients_table.php │ │ ├── 2025_06_30_132538_update_oauth_clients_table.php │ │ ├── 2025_07_15_105949_hash_oauth_clients.php │ │ ├── 2025_07_17_104903_add_reminder_sent_at_to_oauth_access_tokens_table.php │ │ ├── 2025_10_02_000001_add_prevent_overlapping_time_entries_to_organizations_table.php │ │ ├── 2025_10_16_000001_extend_time_entry_description.php │ │ └── 2025_10_24_120845_add_employees_can_manage_tasks_to_organizations_table.php │ ├── schema/ │ │ └── pgsql_test-schema.sql │ └── seeders/ │ └── DatabaseSeeder.php ├── docker/ │ ├── local/ │ │ ├── 8.3/ │ │ │ ├── Dockerfile │ │ │ ├── php.ini │ │ │ ├── start-container │ │ │ └── supervisord.conf │ │ ├── minio/ │ │ │ └── create_bucket.sh │ │ └── pgsql/ │ │ └── create-testing-database.sql │ └── prod/ │ ├── Dockerfile │ ├── LICENSE │ └── deployment/ │ ├── healthcheck │ ├── octane/ │ │ └── FrankenPHP/ │ │ ├── Caddyfile │ │ └── supervisord.frankenphp.conf │ ├── php.ini │ ├── start-container │ ├── supervisord.conf │ ├── supervisord.horizon.conf │ ├── supervisord.reverb.conf │ ├── supervisord.scheduler.conf │ └── supervisord.worker.conf ├── docker-compose.yml ├── e2e/ │ ├── auth.spec.ts │ ├── calendar-settings.spec.ts │ ├── calendar.spec.ts │ ├── clients.spec.ts │ ├── command-palette.spec.ts │ ├── dashboard.spec.ts │ ├── import-export.spec.ts │ ├── members.spec.ts │ ├── organization.spec.ts │ ├── profile.spec.ts │ ├── project-members.spec.ts │ ├── projects.spec.ts │ ├── reporting-detailed.spec.ts │ ├── reporting.spec.ts │ ├── shared-reports.spec.ts │ ├── tags.spec.ts │ ├── tasks.spec.ts │ ├── time.spec.ts │ ├── timetracker.spec.ts │ └── utils/ │ ├── api.ts │ ├── currentTimeEntry.ts │ ├── mailpit.ts │ ├── members.ts │ ├── money.ts │ ├── reporting.ts │ ├── table.ts │ └── tags.ts ├── eslint.config.mjs ├── jsconfig.json ├── lang/ │ └── en/ │ ├── auth.php │ ├── enum.php │ ├── exceptions.php │ ├── importer.php │ ├── pagination.php │ ├── passwords.php │ └── validation.php ├── openapi.json ├── package.json ├── phpstan.neon ├── phpunit.xml ├── pint.json ├── playwright/ │ ├── config.ts │ └── fixtures.ts ├── playwright.config.ts ├── postcss.config.js ├── public/ │ ├── .htaccess │ ├── desktop-version/ │ │ ├── latest-linux.yml │ │ ├── latest-mac.yml │ │ └── latest.yml │ ├── favicons/ │ │ ├── browserconfig.xml │ │ └── site.webmanifest │ ├── index.php │ ├── robots.txt │ └── security.txt ├── resources/ │ ├── css/ │ │ ├── app.css │ │ └── filament/ │ │ └── admin/ │ │ ├── tailwind.config.js │ │ └── theme.css │ ├── js/ │ │ ├── Components/ │ │ │ ├── ActionMessage.vue │ │ │ ├── ActionSection.vue │ │ │ ├── ApplicationLogo.vue │ │ │ ├── ApplicationMark.vue │ │ │ ├── AuthenticationCard.vue │ │ │ ├── AuthenticationCardLogo.vue │ │ │ ├── Banner.vue │ │ │ ├── Billing/ │ │ │ │ └── BillingBanner.vue │ │ │ ├── CommandPalette/ │ │ │ │ ├── CommandPaletteProvider.vue │ │ │ │ └── index.ts │ │ │ ├── Common/ │ │ │ │ ├── Card.vue │ │ │ │ ├── Client/ │ │ │ │ │ ├── ClientCreateModal.vue │ │ │ │ │ ├── ClientEditModal.vue │ │ │ │ │ ├── ClientMoreOptionsDropdown.vue │ │ │ │ │ ├── ClientMultiselectDropdown.vue │ │ │ │ │ ├── ClientTable.vue │ │ │ │ │ ├── ClientTableHeading.vue │ │ │ │ │ └── ClientTableRow.vue │ │ │ │ ├── Invitation/ │ │ │ │ │ ├── InvitationMoreOptionsDropdown.vue │ │ │ │ │ ├── InvitationTable.vue │ │ │ │ │ ├── InvitationTableHeading.vue │ │ │ │ │ └── InvitationTableRow.vue │ │ │ │ ├── Member/ │ │ │ │ │ ├── MemberBillableRateModal.vue │ │ │ │ │ ├── MemberBillableSelect.vue │ │ │ │ │ ├── MemberCombobox.vue │ │ │ │ │ ├── MemberDeleteModal.vue │ │ │ │ │ ├── MemberEditModal.vue │ │ │ │ │ ├── MemberInviteModal.vue │ │ │ │ │ ├── MemberMakePlaceholderModal.vue │ │ │ │ │ ├── MemberMergeModal.vue │ │ │ │ │ ├── MemberMoreOptionsDropdown.vue │ │ │ │ │ ├── MemberMultiselectDropdown.vue │ │ │ │ │ ├── MemberOwnershipTransferConfirmModal.vue │ │ │ │ │ ├── MemberRoleSelect.vue │ │ │ │ │ ├── MemberTable.vue │ │ │ │ │ ├── MemberTableHeading.vue │ │ │ │ │ └── MemberTableRow.vue │ │ │ │ ├── Notification/ │ │ │ │ │ └── Notification.vue │ │ │ │ ├── Organization/ │ │ │ │ │ └── OrganizationBillableRateModal.vue │ │ │ │ ├── PageTitle.vue │ │ │ │ ├── Project/ │ │ │ │ │ ├── BaseFilterBadge.vue │ │ │ │ │ ├── ProjectClientFilterBadge.vue │ │ │ │ │ ├── ProjectDropdown.vue │ │ │ │ │ ├── ProjectEditModal.vue │ │ │ │ │ ├── ProjectMoreOptionsDropdown.vue │ │ │ │ │ ├── ProjectMultiselectDropdown.vue │ │ │ │ │ ├── ProjectStatusFilterBadge.vue │ │ │ │ │ ├── ProjectTable.vue │ │ │ │ │ ├── ProjectTableHeading.vue │ │ │ │ │ ├── ProjectTableRow.vue │ │ │ │ │ ├── ProjectsFilterDropdown.vue │ │ │ │ │ └── constants.ts │ │ │ │ ├── ProjectMember/ │ │ │ │ │ ├── ProjectMemberBillableRateModal.vue │ │ │ │ │ ├── ProjectMemberCreateModal.vue │ │ │ │ │ ├── ProjectMemberEditModal.vue │ │ │ │ │ ├── ProjectMemberMoreOptionsDropdown.vue │ │ │ │ │ ├── ProjectMemberTable.vue │ │ │ │ │ ├── ProjectMemberTableHeading.vue │ │ │ │ │ └── ProjectMemberTableRow.vue │ │ │ │ ├── Report/ │ │ │ │ │ ├── ReportCreateModal.vue │ │ │ │ │ ├── ReportEditModal.vue │ │ │ │ │ ├── ReportMoreOptionsDropdown.vue │ │ │ │ │ ├── ReportSaveButton.vue │ │ │ │ │ ├── ReportTable.vue │ │ │ │ │ ├── ReportTableHeading.vue │ │ │ │ │ └── ReportTableRow.vue │ │ │ │ ├── Reporting/ │ │ │ │ │ ├── ReportingChart.vue │ │ │ │ │ ├── ReportingExportButton.vue │ │ │ │ │ ├── ReportingExportModal.vue │ │ │ │ │ ├── ReportingFilterBadge.vue │ │ │ │ │ ├── ReportingFilterBar.vue │ │ │ │ │ ├── ReportingGroupBySelect.vue │ │ │ │ │ ├── ReportingOverview.vue │ │ │ │ │ ├── ReportingPieChart.vue │ │ │ │ │ ├── ReportingRoundingControls.vue │ │ │ │ │ ├── ReportingRow.vue │ │ │ │ │ └── ReportingTabNavbar.vue │ │ │ │ ├── StatCard.vue │ │ │ │ ├── TabBar/ │ │ │ │ │ ├── TabBar.vue │ │ │ │ │ └── TabBarItem.vue │ │ │ │ ├── TableHeading.vue │ │ │ │ ├── Tag/ │ │ │ │ │ ├── TagEditModal.vue │ │ │ │ │ ├── TagMoreOptionsDropdown.vue │ │ │ │ │ ├── TagTable.vue │ │ │ │ │ ├── TagTableHeading.vue │ │ │ │ │ └── TagTableRow.vue │ │ │ │ ├── Task/ │ │ │ │ │ ├── TaskCreateModal.vue │ │ │ │ │ ├── TaskEditModal.vue │ │ │ │ │ ├── TaskMoreOptionsDropdown.vue │ │ │ │ │ ├── TaskMultiselectDropdown.vue │ │ │ │ │ ├── TaskTable.vue │ │ │ │ │ ├── TaskTableHeading.vue │ │ │ │ │ └── TaskTableRow.vue │ │ │ │ ├── UpgradeBadge.vue │ │ │ │ ├── UpgradeModal.vue │ │ │ │ └── User/ │ │ │ │ └── UserTimezoneMismatchModal.vue │ │ │ ├── ConfirmationModal.vue │ │ │ ├── ConfirmsPassword.vue │ │ │ ├── CurrentSidebarTimer.vue │ │ │ ├── Dashboard/ │ │ │ │ ├── ActivityGraphCard.vue │ │ │ │ ├── DashboardCard.vue │ │ │ │ ├── DayOverviewCardChart.vue │ │ │ │ ├── DayOverviewCardEntry.vue │ │ │ │ ├── LastSevenDaysCard.vue │ │ │ │ ├── ProjectsChartCard.vue │ │ │ │ ├── RecentlyTrackedTasksCard.vue │ │ │ │ ├── RecentlyTrackedTasksCardEntry.vue │ │ │ │ ├── TeamActivityCard.vue │ │ │ │ ├── TeamActivityCardEntry.vue │ │ │ │ ├── ThisWeekOverview.vue │ │ │ │ └── ThisWeekReportingTable.vue │ │ │ ├── DropdownLink.vue │ │ │ ├── FormSection.vue │ │ │ ├── NavLink.vue │ │ │ ├── NavigationSidebarItem.vue │ │ │ ├── NavigationSidebarLink.vue │ │ │ ├── NotificationContainer.vue │ │ │ ├── OrganizationSwitcher.vue │ │ │ ├── ResponsiveNavLink.vue │ │ │ ├── SectionBorder.vue │ │ │ ├── SectionTitle.vue │ │ │ ├── TableRow.vue │ │ │ ├── TimeTracker.vue │ │ │ ├── UpdateSidebarNotification.vue │ │ │ ├── UserSettingsIcon.vue │ │ │ └── ui/ │ │ │ ├── alert-dialog/ │ │ │ │ ├── AlertDialog.vue │ │ │ │ ├── AlertDialogAction.vue │ │ │ │ ├── AlertDialogCancel.vue │ │ │ │ ├── AlertDialogContent.vue │ │ │ │ ├── AlertDialogDescription.vue │ │ │ │ ├── AlertDialogFooter.vue │ │ │ │ ├── AlertDialogHeader.vue │ │ │ │ ├── AlertDialogTitle.vue │ │ │ │ ├── AlertDialogTrigger.vue │ │ │ │ └── index.ts │ │ │ ├── calendar/ │ │ │ │ ├── Calendar.vue │ │ │ │ ├── CalendarCell.vue │ │ │ │ ├── CalendarCellTrigger.vue │ │ │ │ ├── CalendarDateInput.vue │ │ │ │ ├── CalendarGrid.vue │ │ │ │ ├── CalendarGridBody.vue │ │ │ │ ├── CalendarGridHead.vue │ │ │ │ ├── CalendarGridRow.vue │ │ │ │ ├── CalendarHeadCell.vue │ │ │ │ ├── CalendarHeader.vue │ │ │ │ ├── CalendarHeading.vue │ │ │ │ ├── CalendarNextButton.vue │ │ │ │ ├── CalendarPrevButton.vue │ │ │ │ └── index.ts │ │ │ ├── dialog/ │ │ │ │ ├── Dialog.vue │ │ │ │ ├── DialogClose.vue │ │ │ │ ├── DialogContent.vue │ │ │ │ ├── DialogDescription.vue │ │ │ │ ├── DialogFooter.vue │ │ │ │ ├── DialogHeader.vue │ │ │ │ ├── DialogScrollContent.vue │ │ │ │ ├── DialogTitle.vue │ │ │ │ ├── DialogTrigger.vue │ │ │ │ └── index.ts │ │ │ ├── dropdown-menu/ │ │ │ │ ├── DropdownMenu.vue │ │ │ │ ├── DropdownMenuCheckboxItem.vue │ │ │ │ ├── DropdownMenuContent.vue │ │ │ │ ├── DropdownMenuGroup.vue │ │ │ │ ├── DropdownMenuItem.vue │ │ │ │ ├── DropdownMenuLabel.vue │ │ │ │ ├── DropdownMenuRadioGroup.vue │ │ │ │ ├── DropdownMenuRadioItem.vue │ │ │ │ ├── DropdownMenuSeparator.vue │ │ │ │ ├── DropdownMenuShortcut.vue │ │ │ │ ├── DropdownMenuSub.vue │ │ │ │ ├── DropdownMenuSubContent.vue │ │ │ │ ├── DropdownMenuSubTrigger.vue │ │ │ │ ├── DropdownMenuTrigger.vue │ │ │ │ └── index.ts │ │ │ ├── label/ │ │ │ │ ├── Label.vue │ │ │ │ └── index.ts │ │ │ ├── number-field/ │ │ │ │ ├── NumberField.vue │ │ │ │ ├── NumberFieldContent.vue │ │ │ │ ├── NumberFieldDecrement.vue │ │ │ │ ├── NumberFieldIncrement.vue │ │ │ │ ├── NumberFieldInput.vue │ │ │ │ └── index.ts │ │ │ ├── select/ │ │ │ │ ├── Select.vue │ │ │ │ ├── SelectContent.vue │ │ │ │ ├── SelectGroup.vue │ │ │ │ ├── SelectItem.vue │ │ │ │ ├── SelectItemText.vue │ │ │ │ ├── SelectLabel.vue │ │ │ │ ├── SelectScrollDownButton.vue │ │ │ │ ├── SelectScrollUpButton.vue │ │ │ │ ├── SelectSeparator.vue │ │ │ │ ├── SelectTrigger.vue │ │ │ │ ├── SelectValue.vue │ │ │ │ └── index.ts │ │ │ ├── switch/ │ │ │ │ ├── Switch.vue │ │ │ │ └── index.ts │ │ │ ├── table/ │ │ │ │ ├── Table.vue │ │ │ │ ├── TableBody.vue │ │ │ │ ├── TableCaption.vue │ │ │ │ ├── TableCell.vue │ │ │ │ ├── TableEmpty.vue │ │ │ │ ├── TableFooter.vue │ │ │ │ ├── TableHead.vue │ │ │ │ ├── TableHeader.vue │ │ │ │ ├── TableRow.vue │ │ │ │ └── index.ts │ │ │ └── tabs/ │ │ │ ├── Tabs.vue │ │ │ ├── TabsContent.vue │ │ │ ├── TabsList.vue │ │ │ ├── TabsTrigger.vue │ │ │ └── index.ts │ │ ├── Layouts/ │ │ │ └── AppLayout.vue │ │ ├── Pages/ │ │ │ ├── API/ │ │ │ │ ├── Index.vue │ │ │ │ └── Partials/ │ │ │ │ └── ApiTokenManager.vue │ │ │ ├── Auth/ │ │ │ │ ├── ConfirmPassword.vue │ │ │ │ ├── ForgotPassword.vue │ │ │ │ ├── Login.vue │ │ │ │ ├── Register.vue │ │ │ │ ├── ResetPassword.vue │ │ │ │ ├── TwoFactorChallenge.vue │ │ │ │ └── VerifyEmail.vue │ │ │ ├── Calendar.vue │ │ │ ├── Clients.vue │ │ │ ├── Dashboard.vue │ │ │ ├── Import.vue │ │ │ ├── Members.vue │ │ │ ├── PrivacyPolicy.vue │ │ │ ├── Profile/ │ │ │ │ ├── Partials/ │ │ │ │ │ ├── ApiTokensForm.vue │ │ │ │ │ ├── DeleteUserForm.vue │ │ │ │ │ ├── LogoutOtherBrowserSessionsForm.vue │ │ │ │ │ ├── ThemeForm.vue │ │ │ │ │ ├── TwoFactorAuthenticationForm.vue │ │ │ │ │ ├── UpdatePasswordForm.vue │ │ │ │ │ └── UpdateProfileInformationForm.vue │ │ │ │ └── Show.vue │ │ │ ├── ProjectShow.vue │ │ │ ├── Projects.vue │ │ │ ├── Reporting.vue │ │ │ ├── ReportingDetailed.vue │ │ │ ├── ReportingShared.vue │ │ │ ├── SharedReport.vue │ │ │ ├── Tags.vue │ │ │ ├── Teams/ │ │ │ │ ├── Create.vue │ │ │ │ ├── Partials/ │ │ │ │ │ ├── CreateTeamForm.vue │ │ │ │ │ ├── DeleteTeamForm.vue │ │ │ │ │ ├── ExportData.vue │ │ │ │ │ ├── ImportData.vue │ │ │ │ │ ├── OrganizationBillableRate.vue │ │ │ │ │ ├── OrganizationFormatSettings.vue │ │ │ │ │ ├── OrganizationTimeEntrySettings.vue │ │ │ │ │ ├── TeamMemberManager.vue │ │ │ │ │ └── UpdateTeamNameForm.vue │ │ │ │ └── Show.vue │ │ │ ├── TermsOfService.vue │ │ │ ├── Time.vue │ │ │ └── Welcome.vue │ │ ├── app.ts │ │ ├── bootstrap.js │ │ ├── lib/ │ │ │ └── utils.ts │ │ ├── packages/ │ │ │ ├── api/ │ │ │ │ ├── .gitignore │ │ │ │ ├── package.json │ │ │ │ ├── src/ │ │ │ │ │ ├── index.ts │ │ │ │ │ └── openapi.json.client.ts │ │ │ │ ├── tsconfig.json │ │ │ │ └── vite.config.js │ │ │ └── ui/ │ │ │ ├── .gitignore │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── Badge.vue │ │ │ │ ├── BillableRateModal.vue │ │ │ │ ├── Buttons/ │ │ │ │ │ ├── Button.vue │ │ │ │ │ ├── DangerButton.vue │ │ │ │ │ ├── PrimaryButton.vue │ │ │ │ │ ├── SecondaryButton.vue │ │ │ │ │ └── index.ts │ │ │ │ ├── CardTitle.vue │ │ │ │ ├── Client/ │ │ │ │ │ ├── ClientDropdown.vue │ │ │ │ │ └── ClientDropdownItem.vue │ │ │ │ ├── CommandPalette/ │ │ │ │ │ ├── CommandPalette.vue │ │ │ │ │ ├── CommandPaletteTypes.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── DialogModal.vue │ │ │ │ ├── EstimatedTimeProgress.vue │ │ │ │ ├── EstimatedTimeSection.vue │ │ │ │ ├── FullCalendar/ │ │ │ │ │ ├── CalendarSettingsPopover.vue │ │ │ │ │ ├── FullCalendarDayHeader.vue │ │ │ │ │ ├── FullCalendarEventContent.vue │ │ │ │ │ ├── TimeEntryCalendar.vue │ │ │ │ │ ├── calendarSettings.ts │ │ │ │ │ ├── idleStatusPlugin.ts │ │ │ │ │ └── useVisualSnap.ts │ │ │ │ ├── GroupedItemsCountButton.vue │ │ │ │ ├── Icons/ │ │ │ │ │ ├── BillableIcon.vue │ │ │ │ │ ├── DollarIcon.vue │ │ │ │ │ ├── EuroIcon.vue │ │ │ │ │ └── ListFilterIcon.vue │ │ │ │ ├── Input/ │ │ │ │ │ ├── BillableRateInput.vue │ │ │ │ │ ├── BillableToggleButton.vue │ │ │ │ │ ├── Checkbox.vue │ │ │ │ │ ├── DatePicker.vue │ │ │ │ │ ├── DateRangePicker.vue │ │ │ │ │ ├── Dropdown.vue │ │ │ │ │ ├── DurationHumanInput.vue │ │ │ │ │ ├── EstimatedTimeInput.vue │ │ │ │ │ ├── InputError.vue │ │ │ │ │ ├── InputLabel.vue │ │ │ │ │ ├── MultiselectDropdown.vue │ │ │ │ │ ├── TextInput.vue │ │ │ │ │ ├── TextareaInput.vue │ │ │ │ │ ├── TimePickerSimple.vue │ │ │ │ │ └── TimeRangeSelector.vue │ │ │ │ ├── LoadingSpinner.vue │ │ │ │ ├── MainContainer.vue │ │ │ │ ├── Modal.vue │ │ │ │ ├── Project/ │ │ │ │ │ ├── ProjectBadge.vue │ │ │ │ │ ├── ProjectBillableRateModal.vue │ │ │ │ │ ├── ProjectBillableSelect.vue │ │ │ │ │ ├── ProjectColorSelector.vue │ │ │ │ │ ├── ProjectCreateModal.vue │ │ │ │ │ ├── ProjectDropdownItem.vue │ │ │ │ │ └── ProjectEditBillableSection.vue │ │ │ │ ├── Tag/ │ │ │ │ │ ├── TagBadge.vue │ │ │ │ │ ├── TagCreateModal.vue │ │ │ │ │ └── TagDropdown.vue │ │ │ │ ├── TimeEntry/ │ │ │ │ │ ├── TimeEntryAggregateRow.vue │ │ │ │ │ ├── TimeEntryCreateModal.vue │ │ │ │ │ ├── TimeEntryDescriptionInput.vue │ │ │ │ │ ├── TimeEntryEditModal.vue │ │ │ │ │ ├── TimeEntryGroupedTable.vue │ │ │ │ │ ├── TimeEntryMassActionRow.vue │ │ │ │ │ ├── TimeEntryMassUpdateModal.vue │ │ │ │ │ ├── TimeEntryMoreOptionsDropdown.vue │ │ │ │ │ ├── TimeEntryRangeSelector.vue │ │ │ │ │ ├── TimeEntryRow.vue │ │ │ │ │ ├── TimeEntryRowDurationInput.vue │ │ │ │ │ ├── TimeEntryRowHeading.vue │ │ │ │ │ └── TimeEntryRowTagDropdown.vue │ │ │ │ ├── TimeTracker/ │ │ │ │ │ ├── TimeTrackerControls.vue │ │ │ │ │ ├── TimeTrackerMoreOptionsDropdown.vue │ │ │ │ │ ├── TimeTrackerProjectTaskDropdown.vue │ │ │ │ │ ├── TimeTrackerRangeSelector.vue │ │ │ │ │ ├── TimeTrackerRecentlyTrackedEntry.vue │ │ │ │ │ ├── TimeTrackerRunningInDifferentOrganizationOverlay.vue │ │ │ │ │ └── TimeTrackerTagDropdown.vue │ │ │ │ ├── TimeTrackerStartStop.vue │ │ │ │ ├── TimezoneMismatchModal.vue │ │ │ │ ├── accordion/ │ │ │ │ │ ├── Accordion.vue │ │ │ │ │ ├── AccordionContent.vue │ │ │ │ │ ├── AccordionItem.vue │ │ │ │ │ ├── AccordionTrigger.vue │ │ │ │ │ └── index.ts │ │ │ │ ├── command/ │ │ │ │ │ ├── Command.vue │ │ │ │ │ ├── CommandGroup.vue │ │ │ │ │ ├── CommandInput.vue │ │ │ │ │ ├── CommandItem.vue │ │ │ │ │ ├── CommandList.vue │ │ │ │ │ ├── CommandSeparator.vue │ │ │ │ │ ├── CommandShortcut.vue │ │ │ │ │ └── index.ts │ │ │ │ ├── field/ │ │ │ │ │ ├── Field.vue │ │ │ │ │ ├── FieldContent.vue │ │ │ │ │ ├── FieldDescription.vue │ │ │ │ │ ├── FieldError.vue │ │ │ │ │ ├── FieldGroup.vue │ │ │ │ │ ├── FieldLabel.vue │ │ │ │ │ ├── FieldLegend.vue │ │ │ │ │ ├── FieldSeparator.vue │ │ │ │ │ ├── FieldSet.vue │ │ │ │ │ ├── FieldTitle.vue │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ ├── popover/ │ │ │ │ │ ├── Popover.vue │ │ │ │ │ ├── PopoverContent.vue │ │ │ │ │ ├── PopoverTrigger.vue │ │ │ │ │ └── index.ts │ │ │ │ ├── range-calendar/ │ │ │ │ │ ├── RangeCalendar.vue │ │ │ │ │ ├── RangeCalendarCell.vue │ │ │ │ │ ├── RangeCalendarCellTrigger.vue │ │ │ │ │ ├── RangeCalendarGrid.vue │ │ │ │ │ ├── RangeCalendarGridBody.vue │ │ │ │ │ ├── RangeCalendarGridHead.vue │ │ │ │ │ ├── RangeCalendarGridRow.vue │ │ │ │ │ ├── RangeCalendarHeadCell.vue │ │ │ │ │ ├── RangeCalendarHeader.vue │ │ │ │ │ ├── RangeCalendarHeading.vue │ │ │ │ │ ├── RangeCalendarNextButton.vue │ │ │ │ │ ├── RangeCalendarPrevButton.vue │ │ │ │ │ └── index.ts │ │ │ │ ├── separator/ │ │ │ │ │ ├── Separator.vue │ │ │ │ │ └── index.ts │ │ │ │ ├── tooltip/ │ │ │ │ │ ├── Tooltip.vue │ │ │ │ │ ├── TooltipContent.vue │ │ │ │ │ ├── TooltipProvider.vue │ │ │ │ │ ├── TooltipTrigger.vue │ │ │ │ │ └── index.ts │ │ │ │ └── utils/ │ │ │ │ ├── cn.ts │ │ │ │ ├── color.ts │ │ │ │ ├── money.ts │ │ │ │ ├── number.ts │ │ │ │ ├── random.ts │ │ │ │ ├── select.ts │ │ │ │ ├── settings.ts │ │ │ │ └── time.ts │ │ │ ├── styles.css │ │ │ ├── tailwind.theme.js │ │ │ ├── tsconfig.json │ │ │ └── vite.config.js │ │ ├── types/ │ │ │ ├── dom.d.ts │ │ │ ├── dom.ts │ │ │ ├── global.d.ts │ │ │ ├── inertia.d.ts │ │ │ ├── jetstream.ts │ │ │ ├── models.d.ts │ │ │ ├── models.ts │ │ │ ├── projects.d.ts │ │ │ ├── reporting.ts │ │ │ ├── time-entries.d.ts │ │ │ ├── vite-env.d.ts │ │ │ └── vue-shim.d.ts │ │ ├── utils/ │ │ │ ├── billing.ts │ │ │ ├── commandPaletteCommands.ts │ │ │ ├── feedback.ts │ │ │ ├── fetchAllPages.ts │ │ │ ├── format.ts │ │ │ ├── init.ts │ │ │ ├── money.ts │ │ │ ├── notification.ts │ │ │ ├── permissions.ts │ │ │ ├── prefetch.ts │ │ │ ├── roles.ts │ │ │ ├── session.ts │ │ │ ├── theme.ts │ │ │ ├── useAggregatedTimeEntriesQuery.ts │ │ │ ├── useClients.ts │ │ │ ├── useClientsQuery.ts │ │ │ ├── useCommandPalette.ts │ │ │ ├── useCssVariable.ts │ │ │ ├── useCurrentTimeEntry.ts │ │ │ ├── useInvitations.ts │ │ │ ├── useMembers.ts │ │ │ ├── useMembersQuery.ts │ │ │ ├── useOrganization.ts │ │ │ ├── useOrganizationQuery.ts │ │ │ ├── useProjectMembers.ts │ │ │ ├── useProjectMembersQuery.ts │ │ │ ├── useProjects.ts │ │ │ ├── useProjectsQuery.ts │ │ │ ├── useReporting.ts │ │ │ ├── useReportsQuery.ts │ │ │ ├── useTags.ts │ │ │ ├── useTagsQuery.ts │ │ │ ├── useTasks.ts │ │ │ ├── useTasksQuery.ts │ │ │ ├── useTimeEntriesCalendarQuery.ts │ │ │ ├── useTimeEntriesInfiniteQuery.ts │ │ │ ├── useTimeEntriesMutations.ts │ │ │ ├── useTimeEntriesReportQuery.ts │ │ │ └── useUser.ts │ │ ├── ziggy.d.ts │ │ └── ziggy.js │ ├── markdown/ │ │ ├── policy.md │ │ └── terms.md │ ├── testfiles/ │ │ ├── clockify_projects_import_test_1.csv │ │ ├── clockify_time_entries_import_test_1.csv │ │ ├── clockify_time_entries_import_test_2.csv │ │ ├── clockify_time_entries_import_test_3.csv │ │ ├── generic_projects_import_test_1.csv │ │ ├── generic_time_entries_import_test_1.csv │ │ ├── harvest_clients_import_test_1.csv │ │ ├── harvest_projects_import_test_1.csv │ │ ├── harvest_time_entries_import_test_1.csv │ │ ├── solidtime_import_test_1/ │ │ │ ├── clients.csv │ │ │ ├── members.csv │ │ │ ├── meta.json │ │ │ ├── organization_invitations.csv │ │ │ ├── organizations.csv │ │ │ ├── project_members.csv │ │ │ ├── projects.csv │ │ │ ├── tags.csv │ │ │ ├── tasks.csv │ │ │ └── time_entries.csv │ │ ├── toggl_data_import_test_1/ │ │ │ ├── clients.json │ │ │ ├── projects.json │ │ │ ├── projects_users/ │ │ │ │ ├── 401.json │ │ │ │ ├── 402.json │ │ │ │ └── 403.json │ │ │ ├── tags.json │ │ │ ├── tasks/ │ │ │ │ ├── 401.json │ │ │ │ ├── 402.json │ │ │ │ └── 403.json │ │ │ └── workspace_users.json │ │ ├── toggl_data_import_test_2/ │ │ │ ├── clients.json │ │ │ ├── projects.json │ │ │ ├── projects_users/ │ │ │ │ ├── 401.json │ │ │ │ ├── 402.json │ │ │ │ └── 403.json │ │ │ ├── tags.json │ │ │ ├── tasks/ │ │ │ │ ├── 401.json │ │ │ │ ├── 402.json │ │ │ │ └── 403.json │ │ │ └── workspace_users.json │ │ ├── toggl_time_entries_import_test_1.csv │ │ └── toggl_time_entries_import_test_2.csv │ └── views/ │ ├── app.blade.php │ ├── auth/ │ │ └── oauth/ │ │ └── authorize.blade.php │ ├── emails/ │ │ ├── auth-api-expiration-reminder.blade.php │ │ ├── auth-api-token-expired.blade.php │ │ ├── organization-invitation.blade.php │ │ └── time-entry-still-running.blade.php │ ├── filament/ │ │ └── widgets/ │ │ └── server-overview.blade.php │ ├── reports/ │ │ ├── time-entry-aggregate/ │ │ │ ├── pdf-footer.blade.php │ │ │ ├── pdf.blade.php │ │ │ └── spreadsheet.blade.php │ │ └── time-entry-index/ │ │ ├── pdf-footer.blade.php │ │ └── pdf.blade.php │ └── vendor/ │ └── mail/ │ ├── html/ │ │ ├── button.blade.php │ │ ├── footer.blade.php │ │ ├── header.blade.php │ │ ├── layout.blade.php │ │ ├── message.blade.php │ │ ├── panel.blade.php │ │ ├── subcopy.blade.php │ │ ├── table.blade.php │ │ └── themes/ │ │ └── default.css │ └── text/ │ ├── button.blade.php │ ├── footer.blade.php │ ├── header.blade.php │ ├── layout.blade.php │ ├── message.blade.php │ ├── panel.blade.php │ ├── subcopy.blade.php │ └── table.blade.php ├── routes/ │ ├── api.php │ └── web.php ├── storage/ │ ├── app/ │ │ └── .gitignore │ ├── framework/ │ │ ├── .gitignore │ │ ├── cache/ │ │ │ └── .gitignore │ │ ├── sessions/ │ │ │ └── .gitignore │ │ ├── testing/ │ │ │ └── .gitignore │ │ └── views/ │ │ └── .gitignore │ └── logs/ │ └── .gitignore ├── tailwind.config.js ├── tests/ │ ├── CreatesApplication.php │ ├── Feature/ │ │ ├── AuthenticationTest.php │ │ ├── BrowserSessionsTest.php │ │ ├── CreateOrganizationTest.php │ │ ├── DeleteAccountTest.php │ │ ├── DeleteOrganizationTest.php │ │ ├── EmailVerificationTest.php │ │ ├── InviteTeamMemberTest.php │ │ ├── LeaveTeamTest.php │ │ ├── PasswordConfirmationTest.php │ │ ├── PasswordResetTest.php │ │ ├── ProfileInformationTest.php │ │ ├── RegistrationTest.php │ │ ├── RemoveTeamMemberTest.php │ │ ├── TwoFactorAuthenticationSettingsTest.php │ │ ├── UpdatePasswordTest.php │ │ ├── UpdateTeamMemberRoleTest.php │ │ └── UpdateTeamTest.php │ ├── TestCase.php │ ├── TestCaseWithDatabase.php │ └── Unit/ │ ├── Console/ │ │ ├── Commands/ │ │ │ ├── Admin/ │ │ │ │ ├── OrganizationDeleteCommandTest.php │ │ │ │ ├── UserCreateCommandCommandTest.php │ │ │ │ └── UserVerifyCommandTest.php │ │ │ ├── Auth/ │ │ │ │ └── AuthSendReminderForExpiringApiTokensCommandTest.php │ │ │ ├── Correction/ │ │ │ │ └── CorrectionPlaceholderMembersCommandTest.php │ │ │ ├── Report/ │ │ │ │ └── ReportSetExpiredToPrivateCommandTest.php │ │ │ ├── SelfHost/ │ │ │ │ ├── SelfHostCheckForUpdateCommandTest.php │ │ │ │ ├── SelfHostDatabaseConsistencyCommandTest.php │ │ │ │ ├── SelfHostGenerateKeysCommandTest.php │ │ │ │ └── SelfHostTelemetryCommandTest.php │ │ │ └── TimeEntry/ │ │ │ └── TimeEntrySendStillRunningMailsCommandTest.php │ │ └── KernelTest.php │ ├── Database/ │ │ ├── MigrationTest.php │ │ └── SeederTest.php │ ├── Endpoint/ │ │ ├── Api/ │ │ │ └── V1/ │ │ │ ├── ApiEndpointTestAbstract.php │ │ │ ├── ApiTokenEndpointTest.php │ │ │ ├── ChartEndpointTest.php │ │ │ ├── ClientEndpointTest.php │ │ │ ├── CurrencyEndpointTest.php │ │ │ ├── ExportEndpointTest.php │ │ │ ├── ImportEndpointTest.php │ │ │ ├── InvitationEndpointTest.php │ │ │ ├── MemberEndpointTest.php │ │ │ ├── OrganizationEndpointTest.php │ │ │ ├── ProjectEndpointTest.php │ │ │ ├── ProjectMemberEndpointTest.php │ │ │ ├── Public/ │ │ │ │ └── PublicReportEndpointTest.php │ │ │ ├── ReportEndpointTest.php │ │ │ ├── TagEndpointTest.php │ │ │ ├── TaskEndpointTest.php │ │ │ ├── TimeEntryEndpointTest.php │ │ │ ├── UserEndpointTest.php │ │ │ ├── UserMembershipEndpointTest.php │ │ │ └── UserTimeEntryEndpointTest.php │ │ └── Web/ │ │ ├── DashboardEndpointTest.php │ │ ├── EndpointTestAbstract.php │ │ ├── HealthCheckEndpointTest.php │ │ └── HomeEndpointTest.php │ ├── Filament/ │ │ ├── FilamentTestCase.php │ │ ├── Resources/ │ │ │ ├── AuditResourceTest.php │ │ │ ├── ClientResourceTest.php │ │ │ ├── FailedJobResourceTest.php │ │ │ ├── OrganizationInvitationResourceTest.php │ │ │ ├── OrganizationResourceTest.php │ │ │ ├── ProjectResourceTest.php │ │ │ ├── ReportResourceTest.php │ │ │ ├── TagResourceTest.php │ │ │ ├── TaskResourceTest.php │ │ │ ├── TimeEntryResourceTest.php │ │ │ ├── TokenResourceTest.php │ │ │ └── UserResourceTest.php │ │ └── Widgets/ │ │ └── ServerOverviewWidgetTest.php │ ├── Jobs/ │ │ ├── RecalculateSpentTimeForProjectTest.php │ │ ├── RecalculateSpentTimeForTaskTest.php │ │ └── Test/ │ │ └── TestJobTest.php │ ├── Mail/ │ │ ├── AuthApiTokenExpirationReminderMailTest.php │ │ ├── AuthApiTokenExpiredMailTest.php │ │ ├── OrganizationInvitationMailTest.php │ │ └── TimeEntryStillRunningMailTest.php │ ├── Middleware/ │ │ ├── CheckOrganizationBlockedMiddlewareTest.php │ │ ├── EnsureEmailIsVerifiedMiddlewareTest.php │ │ ├── ForceHttpsMiddlewareTest.php │ │ ├── HandleInertiaRequestsMiddlewareTest.php │ │ └── MiddlewareTestAbstract.php │ ├── Model/ │ │ ├── ClientModelTest.php │ │ ├── MemberModelTest.php │ │ ├── ModelTestAbstract.php │ │ ├── OrganizationModelTest.php │ │ ├── Passport/ │ │ │ └── TokenModelTest.php │ │ ├── ProjectMemberModelTest.php │ │ ├── ProjectModelTest.php │ │ ├── ReportModelTest.php │ │ ├── TagModelTest.php │ │ ├── TaskModelTest.php │ │ ├── TimeEntryModelTest.php │ │ └── UserModelTest.php │ ├── Rules/ │ │ ├── ColorRuleTest.php │ │ └── CurrencyRuleTest.php │ └── Service/ │ ├── BillableRateServiceTest.php │ ├── CurrencyServiceTest.php │ ├── DashboardServiceTest.php │ ├── DeletionServiceTest.php │ ├── Export/ │ │ └── ExportServiceTest.php │ ├── Import/ │ │ ├── ImportDatabaseHelperTest.php │ │ ├── ImportServiceTest.php │ │ └── Importers/ │ │ ├── ClockifyProjectsImporterTest.php │ │ ├── ClockifyTimeEntriesImporterTest.php │ │ ├── GenericProjectsImporterTest.php │ │ ├── GenericTimeEntriesImporterTest.php │ │ ├── HarvestClientsImporterTest.php │ │ ├── HarvestProjectsImporterTest.php │ │ ├── HarvestTimeEntriesImporterTest.php │ │ ├── ImporterProviderTest.php │ │ ├── ImporterTestAbstract.php │ │ ├── SolidtimeImporterTest.php │ │ ├── TogglDataImporterTest.php │ │ └── TogglTimeEntriesImporterTest.php │ ├── IntervalServiceTest.php │ ├── LocalizationServiceTest.php │ ├── MemberServiceTest.php │ ├── PermissionStoreTest.php │ ├── TimeEntryAggregationServiceTest.php │ ├── TimeEntryFilterTest.php │ ├── TimezoneServiceTest.php │ └── UserServiceTest.php ├── tsconfig.json ├── vite-module-loader.js └── vite.config.js
Showing preview only (336K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (2769 symbols across 622 files)
FILE: app/Actions/Fortify/CreateNewUser.php
class CreateNewUser (line 22) | class CreateNewUser implements CreatesNewUsers
method create (line 33) | public function create(array $input): User
FILE: app/Actions/Fortify/PasswordValidationRules.php
type PasswordValidationRules (line 10) | trait PasswordValidationRules
method passwordRules (line 17) | protected function passwordRules(): array
FILE: app/Actions/Fortify/ResetUserPassword.php
class ResetUserPassword (line 12) | class ResetUserPassword implements ResetsUserPasswords
method reset (line 21) | public function reset(User $user, array $input): void
FILE: app/Actions/Fortify/UpdateUserPassword.php
class UpdateUserPassword (line 12) | class UpdateUserPassword implements UpdatesUserPasswords
method update (line 21) | public function update(User $user, array $input): void
FILE: app/Actions/Fortify/UpdateUserProfileInformation.php
class UpdateUserProfileInformation (line 16) | class UpdateUserProfileInformation implements UpdatesUserProfileInformation
method update (line 25) | public function update(User $user, array $input): void
FILE: app/Actions/Jetstream/AddOrganizationMember.php
class AddOrganizationMember (line 21) | class AddOrganizationMember implements AddsTeamMembers
method add (line 26) | public function add(User $owner, Organization $organization, string $e...
method validate (line 43) | protected function validate(Organization $organization, string $email,...
method rules (line 58) | protected function rules(): array
method ensureUserIsNotAlreadyOnTeam (line 84) | protected function ensureUserIsNotAlreadyOnTeam(Organization $team, st...
FILE: app/Actions/Jetstream/CreateOrganization.php
class CreateOrganization (line 19) | class CreateOrganization implements CreatesTeams
method create (line 29) | public function create(User $user, array $input): Organization
FILE: app/Actions/Jetstream/DeleteOrganization.php
class DeleteOrganization (line 11) | class DeleteOrganization implements DeletesTeams
method delete (line 16) | public function delete(Organization $organization): void
FILE: app/Actions/Jetstream/DeleteUser.php
class DeleteUser (line 13) | class DeleteUser implements DeletesUsers
method delete (line 20) | public function delete(User $user): void
FILE: app/Actions/Jetstream/InviteOrganizationMember.php
class InviteOrganizationMember (line 13) | class InviteOrganizationMember implements InvitesTeamMembers
method invite (line 20) | public function invite(User $user, Organization $organization, string ...
FILE: app/Actions/Jetstream/RemoveOrganizationMember.php
class RemoveOrganizationMember (line 13) | class RemoveOrganizationMember implements RemovesTeamMembers
method remove (line 20) | public function remove(User $user, Organization $organization, User $t...
FILE: app/Actions/Jetstream/UpdateMemberRole.php
class UpdateMemberRole (line 14) | class UpdateMemberRole
method update (line 21) | public function update(User $actingUser, Organization $organization, s...
FILE: app/Actions/Jetstream/UpdateOrganization.php
class UpdateOrganization (line 16) | class UpdateOrganization implements UpdatesTeamNames
method update (line 26) | public function update(User $user, Organization $organization, array $...
FILE: app/Actions/Jetstream/ValidateOrganizationDeletion.php
class ValidateOrganizationDeletion (line 12) | class ValidateOrganizationDeletion
method validate (line 22) | public function validate(User $user, Organization $organization): void
FILE: app/Console/Commands/Admin/OrganizationDeleteCommand.php
class OrganizationDeleteCommand (line 12) | class OrganizationDeleteCommand extends Command
method handle (line 32) | public function handle(DeletionService $deletionService): int
FILE: app/Console/Commands/Admin/UserCreateCommand.php
class UserCreateCommand (line 15) | class UserCreateCommand extends Command
method handle (line 38) | public function handle(): int
FILE: app/Console/Commands/Admin/UserVerifyCommand.php
class UserVerifyCommand (line 11) | class UserVerifyCommand extends Command
method handle (line 31) | public function handle(): int
FILE: app/Console/Commands/Auth/AuthSendReminderForExpiringApiTokensCommand.php
class AuthSendReminderForExpiringApiTokensCommand (line 17) | class AuthSendReminderForExpiringApiTokensCommand extends Command
method handle (line 37) | public function handle(): int
FILE: app/Console/Commands/Correction/CorrectionPlaceholderMembersCommand.php
class CorrectionPlaceholderMembersCommand (line 13) | class CorrectionPlaceholderMembersCommand extends Command
method handle (line 33) | public function handle(): int
FILE: app/Console/Commands/Report/ReportSetExpiredToPrivateCommand.php
class ReportSetExpiredToPrivateCommand (line 13) | class ReportSetExpiredToPrivateCommand extends Command
method handle (line 33) | public function handle(): int
FILE: app/Console/Commands/SelfHost/SelfHostCheckForUpdateCommand.php
class SelfHostCheckForUpdateCommand (line 11) | class SelfHostCheckForUpdateCommand extends Command
method handle (line 30) | public function handle(): int
FILE: app/Console/Commands/SelfHost/SelfHostDatabaseConsistency.php
class SelfHostDatabaseConsistency (line 14) | class SelfHostDatabaseConsistency extends Command
method handle (line 33) | public function handle(): int
method logProblems (line 106) | private function logProblems(Collection $problems, string $message, bo...
FILE: app/Console/Commands/SelfHost/SelfHostGenerateKeysCommand.php
class SelfHostGenerateKeysCommand (line 12) | class SelfHostGenerateKeysCommand extends Command
method handle (line 34) | public function handle(): int
FILE: app/Console/Commands/SelfHost/SelfHostTelemetryCommand.php
class SelfHostTelemetryCommand (line 10) | class SelfHostTelemetryCommand extends Command
method handle (line 29) | public function handle(): int
FILE: app/Console/Commands/Test/TestEmailCommand.php
class TestEmailCommand (line 11) | class TestEmailCommand extends Command
method handle (line 30) | public function handle(): int
FILE: app/Console/Commands/Test/TestJobCommand.php
class TestJobCommand (line 11) | class TestJobCommand extends Command
method handle (line 30) | public function handle(): int
FILE: app/Console/Commands/Test/TestOutputCommand.php
class TestOutputCommand (line 9) | class TestOutputCommand extends Command
method handle (line 28) | public function handle(): int
FILE: app/Console/Commands/TimeEntry/TimeEntrySendStillRunningMailsCommand.php
class TimeEntrySendStillRunningMailsCommand (line 16) | class TimeEntrySendStillRunningMailsCommand extends Command
method handle (line 36) | public function handle(): int
FILE: app/Console/Kernel.php
class Kernel (line 10) | class Kernel extends ConsoleKernel
method schedule (line 15) | protected function schedule(Schedule $schedule): void
method commands (line 55) | protected function commands(): void
FILE: app/Enums/CurrencyFormat.php
method toSelectArray (line 27) | public static function toSelectArray(): array
FILE: app/Enums/DateFormat.php
method toCarbonFormat (line 24) | public function toCarbonFormat(): string
method toSelectArray (line 39) | public static function toSelectArray(): array
FILE: app/Enums/ExportFormat.php
method getFileExtension (line 16) | public function getFileExtension(): string
method getExportPackageType (line 26) | public function getExportPackageType(): string
FILE: app/Enums/IntervalFormat.php
method toSelectArray (line 23) | public static function toSelectArray(): array
FILE: app/Enums/NumberFormat.php
method toSelectArray (line 28) | public static function toSelectArray(): array
FILE: app/Enums/TimeEntryAggregationType.php
method fromInterval (line 25) | public static function fromInterval(TimeEntryAggregationTypeInterval $ti...
method toInterval (line 35) | public function toInterval(): ?TimeEntryAggregationTypeInterval
FILE: app/Enums/TimeFormat.php
method toSelectArray (line 19) | public static function toSelectArray(): array
FILE: app/Enums/Weekday.php
method toEndOfWeek (line 22) | public function toEndOfWeek(): self
method carbonWeekDay (line 35) | public function carbonWeekDay(): int
method toSelectArray (line 51) | public static function toSelectArray(): array
FILE: app/Events/AfterCreateOrganization.php
class AfterCreateOrganization (line 15) | class AfterCreateOrganization
method __construct (line 22) | public function __construct(Organization $organization)
FILE: app/Events/BeforeOrganizationDeletion.php
class BeforeOrganizationDeletion (line 10) | class BeforeOrganizationDeletion
method __construct (line 16) | public function __construct(Organization $organization)
FILE: app/Events/DatabaseSeederAfterSeed.php
class DatabaseSeederAfterSeed (line 9) | class DatabaseSeederAfterSeed
method __construct (line 13) | public function __construct() {}
FILE: app/Events/DatabaseSeederBeforeDelete.php
class DatabaseSeederBeforeDelete (line 9) | class DatabaseSeederBeforeDelete
method __construct (line 13) | public function __construct() {}
FILE: app/Events/MemberMadeToPlaceholder.php
class MemberMadeToPlaceholder (line 11) | class MemberMadeToPlaceholder
method __construct (line 19) | public function __construct(Member $member, Organization $organization)
FILE: app/Events/MemberRemoved.php
class MemberRemoved (line 11) | class MemberRemoved
method __construct (line 19) | public function __construct(Member $member, Organization $organization)
FILE: app/Events/NewsletterRegistered.php
class NewsletterRegistered (line 9) | class NewsletterRegistered
method __construct (line 22) | public function __construct(string $name, string $email, string $id)
FILE: app/Exceptions/Api/ApiException.php
class ApiException (line 12) | abstract class ApiException extends Exception
method __construct (line 16) | public function __construct()
method render (line 24) | public function render(Request $request): JsonResponse
method getKey (line 37) | public function getKey(): string
method getTranslatedMessage (line 51) | public function getTranslatedMessage(): string
method report (line 61) | public function report(): bool
FILE: app/Exceptions/Api/CanNotDeleteUserWhoIsOwnerOfOrganizationWithMultipleMembers.php
class CanNotDeleteUserWhoIsOwnerOfOrganizationWithMultipleMembers (line 7) | class CanNotDeleteUserWhoIsOwnerOfOrganizationWithMultipleMembers extend...
FILE: app/Exceptions/Api/CanNotRemoveOwnerFromOrganization.php
class CanNotRemoveOwnerFromOrganization (line 7) | class CanNotRemoveOwnerFromOrganization extends ApiException
FILE: app/Exceptions/Api/ChangingRoleOfPlaceholderIsNotAllowed.php
class ChangingRoleOfPlaceholderIsNotAllowed (line 7) | class ChangingRoleOfPlaceholderIsNotAllowed extends ApiException
FILE: app/Exceptions/Api/ChangingRoleToPlaceholderIsNotAllowed.php
class ChangingRoleToPlaceholderIsNotAllowed (line 7) | class ChangingRoleToPlaceholderIsNotAllowed extends ApiException
FILE: app/Exceptions/Api/EntityStillInUseApiException.php
class EntityStillInUseApiException (line 7) | class EntityStillInUseApiException extends ApiException
method __construct (line 13) | public function __construct(string $modelToDelete, string $modelInUse)
method getTranslatedMessage (line 25) | #[\Override]
FILE: app/Exceptions/Api/FeatureIsNotAvailableInFreePlanApiException.php
class FeatureIsNotAvailableInFreePlanApiException (line 7) | class FeatureIsNotAvailableInFreePlanApiException extends ApiException
FILE: app/Exceptions/Api/InactiveUserCanNotBeUsedApiException.php
class InactiveUserCanNotBeUsedApiException (line 7) | class InactiveUserCanNotBeUsedApiException extends ApiException
FILE: app/Exceptions/Api/InvitationForTheEmailAlreadyExistsApiException.php
class InvitationForTheEmailAlreadyExistsApiException (line 7) | class InvitationForTheEmailAlreadyExistsApiException extends ApiException
FILE: app/Exceptions/Api/OnlyOwnerCanChangeOwnership.php
class OnlyOwnerCanChangeOwnership (line 7) | class OnlyOwnerCanChangeOwnership extends ApiException
FILE: app/Exceptions/Api/OnlyPlaceholdersCanBeMergedIntoAnotherMember.php
class OnlyPlaceholdersCanBeMergedIntoAnotherMember (line 7) | class OnlyPlaceholdersCanBeMergedIntoAnotherMember extends ApiException
FILE: app/Exceptions/Api/OrganizationHasNoSubscriptionButMultipleMembersException.php
class OrganizationHasNoSubscriptionButMultipleMembersException (line 7) | class OrganizationHasNoSubscriptionButMultipleMembersException extends A...
FILE: app/Exceptions/Api/OrganizationNeedsAtLeastOneOwner.php
class OrganizationNeedsAtLeastOneOwner (line 7) | class OrganizationNeedsAtLeastOneOwner extends ApiException
FILE: app/Exceptions/Api/OverlappingTimeEntryApiException.php
class OverlappingTimeEntryApiException (line 7) | class OverlappingTimeEntryApiException extends ApiException
FILE: app/Exceptions/Api/PdfRendererIsNotConfiguredException.php
class PdfRendererIsNotConfiguredException (line 7) | class PdfRendererIsNotConfiguredException extends ApiException
FILE: app/Exceptions/Api/PersonalAccessClientIsNotConfiguredException.php
class PersonalAccessClientIsNotConfiguredException (line 7) | class PersonalAccessClientIsNotConfiguredException extends ApiException
FILE: app/Exceptions/Api/ThisPlaceholderCanNotBeInvitedUseTheMergeToolInsteadException.php
class ThisPlaceholderCanNotBeInvitedUseTheMergeToolInsteadException (line 7) | class ThisPlaceholderCanNotBeInvitedUseTheMergeToolInsteadException exte...
FILE: app/Exceptions/Api/TimeEntryCanNotBeRestartedApiException.php
class TimeEntryCanNotBeRestartedApiException (line 7) | class TimeEntryCanNotBeRestartedApiException extends ApiException
FILE: app/Exceptions/Api/TimeEntryStillRunningApiException.php
class TimeEntryStillRunningApiException (line 7) | class TimeEntryStillRunningApiException extends ApiException
FILE: app/Exceptions/Api/UserIsAlreadyMemberOfOrganizationApiException.php
class UserIsAlreadyMemberOfOrganizationApiException (line 7) | class UserIsAlreadyMemberOfOrganizationApiException extends ApiException
FILE: app/Exceptions/Api/UserIsAlreadyMemberOfProjectApiException.php
class UserIsAlreadyMemberOfProjectApiException (line 7) | class UserIsAlreadyMemberOfProjectApiException extends ApiException
FILE: app/Exceptions/Api/UserNotPlaceholderApiException.php
class UserNotPlaceholderApiException (line 7) | class UserNotPlaceholderApiException extends ApiException
FILE: app/Exceptions/Handler.php
class Handler (line 12) | class Handler extends ExceptionHandler
method register (line 28) | public function register(): void
method render (line 35) | public function render($request, Throwable $e): Response|RedirectResponse
FILE: app/Exceptions/MovedToApiException.php
class MovedToApiException (line 9) | class MovedToApiException extends HttpException
method __construct (line 11) | public function __construct()
FILE: app/Extensions/Auditing/Resolvers/CustomIpAddressResolver.php
class CustomIpAddressResolver (line 11) | class CustomIpAddressResolver implements Resolver
method anonymizeIpAddress (line 13) | private static function anonymizeIpAddress(string $ipAddress): string
method resolve (line 23) | public static function resolve(Auditable $auditable): string
FILE: app/Extensions/Fortify/CustomLoginResponse.php
class CustomLoginResponse (line 12) | class CustomLoginResponse extends LoginResponse
method toResponse (line 19) | public function toResponse($request): Response
FILE: app/Extensions/Fortify/CustomTwoFactorLoginResponse.php
class CustomTwoFactorLoginResponse (line 13) | class CustomTwoFactorLoginResponse implements TwoFactorLoginResponseCont...
method toResponse (line 20) | public function toResponse($request): Response
FILE: app/Extensions/Scramble/ApiExceptionTypeToSchema.php
class ApiExceptionTypeToSchema (line 17) | class ApiExceptionTypeToSchema extends ExceptionToResponseExtension
method shouldHandle (line 19) | public function shouldHandle(Type $type): bool
method toResponse (line 25) | public function toResponse(Type $type): Response
method reference (line 53) | public function reference(ObjectType $type): Reference
FILE: app/Extensions/Scramble/PaginatedResourceCollectionTypeToSchema.php
class PaginatedResourceCollectionTypeToSchema (line 23) | class PaginatedResourceCollectionTypeToSchema extends TypeToSchemaExtension
method shouldHandle (line 25) | public function shouldHandle(Type $type): bool
method toSchema (line 31) | public function toSchema(Type $type): ?OpenApiObjectType
method toResponse (line 94) | public function toResponse(Type $type): ?Response
FILE: app/Filament/Resources/AuditResource.php
class AuditResource (line 18) | class AuditResource extends Resource
method form (line 26) | public static function form(Form $form): Form
method table (line 52) | public static function table(Table $table): Table
method getRelations (line 81) | public static function getRelations(): array
method getPages (line 87) | public static function getPages(): array
FILE: app/Filament/Resources/AuditResource/Pages/CreateAudit.php
class CreateAudit (line 10) | class CreateAudit extends CreateRecord
FILE: app/Filament/Resources/AuditResource/Pages/ListAudits.php
class ListAudits (line 10) | class ListAudits extends ListRecords
method getHeaderActions (line 14) | protected function getHeaderActions(): array
FILE: app/Filament/Resources/AuditResource/Pages/ViewAudit.php
class ViewAudit (line 10) | class ViewAudit extends ViewRecord
FILE: app/Filament/Resources/ClientResource.php
class ClientResource (line 17) | class ClientResource extends Resource
method form (line 27) | public static function form(Form $form): Form
method table (line 42) | public static function table(Table $table): Table
method getRelations (line 81) | public static function getRelations(): array
method getPages (line 88) | public static function getPages(): array
FILE: app/Filament/Resources/ClientResource/Pages/CreateClient.php
class CreateClient (line 10) | class CreateClient extends CreateRecord
FILE: app/Filament/Resources/ClientResource/Pages/EditClient.php
class EditClient (line 11) | class EditClient extends EditRecord
method getHeaderActions (line 15) | protected function getHeaderActions(): array
FILE: app/Filament/Resources/ClientResource/Pages/ListClients.php
class ListClients (line 11) | class ListClients extends ListRecords
method getHeaderActions (line 15) | protected function getHeaderActions(): array
FILE: app/Filament/Resources/FailedJobResource.php
class FailedJobResource (line 29) | class FailedJobResource extends Resource
method getNavigationBadge (line 37) | public static function getNavigationBadge(): ?string
method form (line 42) | public static function form(Form $form): Form
method table (line 58) | public static function table(Table $table): Table
method getPages (line 111) | public static function getPages(): array
FILE: app/Filament/Resources/FailedJobResource/Pages/ListFailedJobs.php
class ListFailedJobs (line 14) | class ListFailedJobs extends ListRecords
method getHeaderActions (line 18) | public function getHeaderActions(): array
FILE: app/Filament/Resources/FailedJobResource/Pages/ViewFailedJobs.php
class ViewFailedJobs (line 10) | class ViewFailedJobs extends ViewRecord
FILE: app/Filament/Resources/OrganizationInvitationResource.php
class OrganizationInvitationResource (line 19) | class OrganizationInvitationResource extends Resource
method form (line 31) | public static function form(Form $form): Form
method table (line 59) | public static function table(Table $table): Table
method getRelations (line 100) | public static function getRelations(): array
method getPages (line 106) | public static function getPages(): array
FILE: app/Filament/Resources/OrganizationInvitationResource/Pages/EditOrganizationInvitation.php
class EditOrganizationInvitation (line 11) | class EditOrganizationInvitation extends EditRecord
method getHeaderActions (line 15) | protected function getHeaderActions(): array
FILE: app/Filament/Resources/OrganizationInvitationResource/Pages/ListOrganizationInvitations.php
class ListOrganizationInvitations (line 10) | class ListOrganizationInvitations extends ListRecords
method getHeaderActions (line 14) | protected function getHeaderActions(): array
FILE: app/Filament/Resources/OrganizationInvitationResource/Pages/ViewOrganizationInvitation.php
class ViewOrganizationInvitation (line 11) | class ViewOrganizationInvitation extends ViewRecord
method getHeaderActions (line 15) | protected function getHeaderActions(): array
FILE: app/Filament/Resources/OrganizationResource.php
class OrganizationResource (line 35) | class OrganizationResource extends Resource
method form (line 45) | public static function form(Form $form): Form
method table (line 113) | public static function table(Table $table): Table
method getRelations (line 237) | public static function getRelations(): array
method getPages (line 245) | public static function getPages(): array
FILE: app/Filament/Resources/OrganizationResource/Actions/DeleteOrganization.php
class DeleteOrganization (line 13) | class DeleteOrganization extends DeleteAction
method setUp (line 15) | protected function setUp(): void
FILE: app/Filament/Resources/OrganizationResource/Pages/CreateOrganization.php
class CreateOrganization (line 12) | class CreateOrganization extends CreateRecord
method mutateFormDataBeforeCreate (line 16) | protected function mutateFormDataBeforeCreate(array $data): array
method afterCreate (line 23) | protected function afterCreate(): void
FILE: app/Filament/Resources/OrganizationResource/Pages/EditOrganization.php
class EditOrganization (line 10) | class EditOrganization extends EditRecord
method getHeaderActions (line 14) | protected function getHeaderActions(): array
FILE: app/Filament/Resources/OrganizationResource/Pages/ListOrganizations.php
class ListOrganizations (line 11) | class ListOrganizations extends ListRecords
method getHeaderActions (line 15) | protected function getHeaderActions(): array
FILE: app/Filament/Resources/OrganizationResource/Pages/ViewOrganization.php
class ViewOrganization (line 11) | class ViewOrganization extends ViewRecord
method getHeaderActions (line 15) | protected function getHeaderActions(): array
FILE: app/Filament/Resources/OrganizationResource/RelationManagers/InvitationsRelationManager.php
class InvitationsRelationManager (line 22) | class InvitationsRelationManager extends RelationManager
method form (line 28) | public function form(Form $form): Form
method table (line 49) | public function table(Table $table): Table
FILE: app/Filament/Resources/OrganizationResource/RelationManagers/UsersRelationManager.php
class UsersRelationManager (line 27) | class UsersRelationManager extends RelationManager
method form (line 31) | public function form(Form $form): Form
method table (line 44) | public function table(Table $table): Table
FILE: app/Filament/Resources/ProjectMemberResource.php
class ProjectMemberResource (line 15) | class ProjectMemberResource extends Resource
method form (line 21) | public static function form(Form $form): Form
method table (line 44) | public static function table(Table $table): Table
method getRelations (line 76) | public static function getRelations(): array
method getPages (line 83) | public static function getPages(): array
FILE: app/Filament/Resources/ProjectMemberResource/Pages/CreateProjectMember.php
class CreateProjectMember (line 10) | class CreateProjectMember extends CreateRecord
FILE: app/Filament/Resources/ProjectMemberResource/Pages/EditProjectMember.php
class EditProjectMember (line 11) | class EditProjectMember extends EditRecord
method getHeaderActions (line 15) | protected function getHeaderActions(): array
FILE: app/Filament/Resources/ProjectMemberResource/Pages/ListProjectMembers.php
class ListProjectMembers (line 11) | class ListProjectMembers extends ListRecords
method getHeaderActions (line 15) | protected function getHeaderActions(): array
FILE: app/Filament/Resources/ProjectMemberResource/Pages/ViewProjectMembers.php
class ViewProjectMembers (line 11) | class ViewProjectMembers extends ViewRecord
method getHeaderActions (line 15) | protected function getHeaderActions(): array
FILE: app/Filament/Resources/ProjectResource.php
class ProjectResource (line 20) | class ProjectResource extends Resource
method form (line 30) | public static function form(Form $form): Form
method table (line 58) | public static function table(Table $table): Table
method getRelations (line 94) | public static function getRelations(): array
method getPages (line 101) | public static function getPages(): array
FILE: app/Filament/Resources/ProjectResource/Pages/CreateProject.php
class CreateProject (line 10) | class CreateProject extends CreateRecord
FILE: app/Filament/Resources/ProjectResource/Pages/EditProject.php
class EditProject (line 11) | class EditProject extends EditRecord
method getHeaderActions (line 15) | protected function getHeaderActions(): array
FILE: app/Filament/Resources/ProjectResource/Pages/ListProjects.php
class ListProjects (line 11) | class ListProjects extends ListRecords
method getHeaderActions (line 15) | protected function getHeaderActions(): array
FILE: app/Filament/Resources/ProjectResource/RelationManagers/ProjectMembersRelationManager.php
class ProjectMembersRelationManager (line 15) | class ProjectMembersRelationManager extends RelationManager
method form (line 21) | public function form(Form $form): Form
method table (line 28) | public function table(Table $table): Table
FILE: app/Filament/Resources/ReportResource.php
class ReportResource (line 23) | class ReportResource extends Resource
method form (line 33) | public static function form(Form $form): Form
method table (line 77) | public static function table(Table $table): Table
method getRelations (line 127) | public static function getRelations(): array
method getPages (line 133) | public static function getPages(): array
FILE: app/Filament/Resources/ReportResource/Pages/EditReport.php
class EditReport (line 11) | class EditReport extends EditRecord
method getHeaderActions (line 15) | protected function getHeaderActions(): array
FILE: app/Filament/Resources/ReportResource/Pages/ListReports.php
class ListReports (line 10) | class ListReports extends ListRecords
method getHeaderActions (line 14) | protected function getHeaderActions(): array
FILE: app/Filament/Resources/ReportResource/Pages/ViewReport.php
class ViewReport (line 11) | class ViewReport extends ViewRecord
method getHeaderActions (line 15) | protected function getHeaderActions(): array
FILE: app/Filament/Resources/TagResource.php
class TagResource (line 17) | class TagResource extends Resource
method form (line 27) | public static function form(Form $form): Form
method table (line 42) | public static function table(Table $table): Table
method getRelations (line 81) | public static function getRelations(): array
method getPages (line 88) | public static function getPages(): array
FILE: app/Filament/Resources/TagResource/Pages/CreateTag.php
class CreateTag (line 10) | class CreateTag extends CreateRecord
FILE: app/Filament/Resources/TagResource/Pages/EditTag.php
class EditTag (line 11) | class EditTag extends EditRecord
method getHeaderActions (line 15) | protected function getHeaderActions(): array
FILE: app/Filament/Resources/TagResource/Pages/ListTags.php
class ListTags (line 11) | class ListTags extends ListRecords
method getHeaderActions (line 15) | protected function getHeaderActions(): array
FILE: app/Filament/Resources/TaskResource.php
class TaskResource (line 17) | class TaskResource extends Resource
method form (line 27) | public static function form(Form $form): Form
method table (line 46) | public static function table(Table $table): Table
method getRelations (line 83) | public static function getRelations(): array
method getPages (line 90) | public static function getPages(): array
FILE: app/Filament/Resources/TaskResource/Pages/CreateTask.php
class CreateTask (line 10) | class CreateTask extends CreateRecord
FILE: app/Filament/Resources/TaskResource/Pages/EditTask.php
class EditTask (line 11) | class EditTask extends EditRecord
method getHeaderActions (line 15) | protected function getHeaderActions(): array
FILE: app/Filament/Resources/TaskResource/Pages/ListTasks.php
class ListTasks (line 11) | class ListTasks extends ListRecords
method getHeaderActions (line 15) | protected function getHeaderActions(): array
FILE: app/Filament/Resources/TimeEntryResource.php
class TimeEntryResource (line 22) | class TimeEntryResource extends Resource
method form (line 32) | public static function form(Form $form): Form
method table (line 76) | public static function table(Table $table): Table
method getRelations (line 124) | public static function getRelations(): array
method getPages (line 131) | public static function getPages(): array
FILE: app/Filament/Resources/TimeEntryResource/Pages/CreateTimeEntry.php
class CreateTimeEntry (line 11) | class CreateTimeEntry extends CreateRecord
method mutateFormDataBeforeCreate (line 19) | protected function mutateFormDataBeforeCreate(array $data): array
FILE: app/Filament/Resources/TimeEntryResource/Pages/EditTimeEntry.php
class EditTimeEntry (line 12) | class EditTimeEntry extends EditRecord
method getHeaderActions (line 16) | protected function getHeaderActions(): array
method mutateFormDataBeforeSave (line 28) | protected function mutateFormDataBeforeSave(array $data): array
FILE: app/Filament/Resources/TimeEntryResource/Pages/ListTimeEntries.php
class ListTimeEntries (line 11) | class ListTimeEntries extends ListRecords
method getHeaderActions (line 15) | protected function getHeaderActions(): array
FILE: app/Filament/Resources/TokenResource.php
class TokenResource (line 17) | class TokenResource extends Resource
method form (line 27) | public static function form(Form $form): Form
method table (line 68) | public static function table(Table $table): Table
method getRelations (line 130) | public static function getRelations(): array
method getPages (line 136) | public static function getPages(): array
FILE: app/Filament/Resources/TokenResource/Pages/ListTokens.php
class ListTokens (line 10) | class ListTokens extends ListRecords
method getHeaderActions (line 14) | protected function getHeaderActions(): array
FILE: app/Filament/Resources/TokenResource/Pages/ViewToken.php
class ViewToken (line 10) | class ViewToken extends ViewRecord
method getHeaderActions (line 14) | protected function getHeaderActions(): array
FILE: app/Filament/Resources/UserResource.php
class UserResource (line 32) | class UserResource extends Resource
method form (line 42) | public static function form(Form $form): Form
method table (line 130) | public static function table(Table $table): Table
method getRelations (line 222) | public static function getRelations(): array
method getPages (line 230) | public static function getPages(): array
FILE: app/Filament/Resources/UserResource/Actions/DeleteUser.php
class DeleteUser (line 13) | class DeleteUser extends DeleteAction
method setUp (line 15) | protected function setUp(): void
FILE: app/Filament/Resources/UserResource/Pages/CreateUser.php
class CreateUser (line 13) | class CreateUser extends CreateRecord
method handleRecordCreation (line 17) | protected function handleRecordCreation(array $data): User
FILE: app/Filament/Resources/UserResource/Pages/EditUser.php
class EditUser (line 11) | class EditUser extends EditRecord
method getHeaderActions (line 15) | protected function getHeaderActions(): array
FILE: app/Filament/Resources/UserResource/Pages/ListUsers.php
class ListUsers (line 11) | class ListUsers extends ListRecords
method getHeaderActions (line 15) | protected function getHeaderActions(): array
FILE: app/Filament/Resources/UserResource/Pages/ViewUser.php
class ViewUser (line 12) | class ViewUser extends ViewRecord
method getHeaderActions (line 16) | protected function getHeaderActions(): array
FILE: app/Filament/Resources/UserResource/RelationManagers/OrganizationsRelationManager.php
class OrganizationsRelationManager (line 23) | class OrganizationsRelationManager extends RelationManager
method form (line 27) | public function form(Form $form): Form
method table (line 36) | public function table(Table $table): Table
FILE: app/Filament/Resources/UserResource/RelationManagers/OwnedOrganizationsRelationManager.php
class OwnedOrganizationsRelationManager (line 15) | class OwnedOrganizationsRelationManager extends RelationManager
method form (line 21) | public function form(Form $form): Form
method table (line 28) | public function table(Table $table): Table
FILE: app/Filament/Widgets/ActiveUserOverview.php
class ActiveUserOverview (line 13) | class ActiveUserOverview extends BaseWidget
method getCards (line 19) | protected function getCards(): array
FILE: app/Filament/Widgets/ServerOverview.php
class ServerOverview (line 10) | class ServerOverview extends Widget
method getViewData (line 17) | protected function getViewData(): array
FILE: app/Filament/Widgets/TimeEntriesCreated.php
class TimeEntriesCreated (line 12) | class TimeEntriesCreated extends ChartWidget
method getData (line 20) | protected function getData(): array
method getFilters (line 64) | protected function getFilters(): ?array
method getType (line 73) | protected function getType(): string
FILE: app/Filament/Widgets/TimeEntriesImported.php
class TimeEntriesImported (line 12) | class TimeEntriesImported extends ChartWidget
method getData (line 20) | protected function getData(): array
method getFilters (line 64) | protected function getFilters(): ?array
method getType (line 73) | protected function getType(): string
FILE: app/Filament/Widgets/UserRegistrations.php
class UserRegistrations (line 12) | class UserRegistrations extends ChartWidget
method getData (line 20) | protected function getData(): array
method getFilters (line 65) | protected function getFilters(): ?array
method getType (line 74) | protected function getType(): string
FILE: app/Http/Controllers/Api/V1/ApiTokenController.php
class ApiTokenController (line 18) | class ApiTokenController extends Controller
method index (line 29) | public function index(): ApiTokenCollection
method store (line 54) | public function store(ApiTokenStoreRequest $request): ApiTokenWithAcce...
method revoke (line 83) | public function revoke(Token $apiToken): JsonResponse
method destroy (line 106) | public function destroy(Token $apiToken): JsonResponse
FILE: app/Http/Controllers/Api/V1/ChartController.php
class ChartController (line 14) | class ChartController extends Controller
method weeklyProjectOverview (line 25) | public function weeklyProjectOverview(Organization $organization, Dash...
method latestTasks (line 44) | public function latestTasks(Organization $organization, DashboardServi...
method lastSevenDays (line 63) | public function lastSevenDays(Organization $organization, DashboardSer...
method latestTeamActivity (line 82) | public function latestTeamActivity(Organization $organization, Dashboa...
method dailyTrackedHours (line 100) | public function dailyTrackedHours(Organization $organization, Dashboar...
method totalWeeklyTime (line 119) | public function totalWeeklyTime(Organization $organization, DashboardS...
method totalWeeklyBillableTime (line 138) | public function totalWeeklyBillableTime(Organization $organization, Da...
method totalWeeklyBillableAmount (line 157) | public function totalWeeklyBillableAmount(Organization $organization, ...
method weeklyHistory (line 181) | public function weeklyHistory(Organization $organization, DashboardSer...
FILE: app/Http/Controllers/Api/V1/ClientController.php
class ClientController (line 19) | class ClientController extends Controller
method checkPermission (line 21) | protected function checkPermission(Organization $organization, string ...
method index (line 38) | public function index(Organization $organization, ClientIndexRequest $...
method store (line 71) | public function store(Organization $organization, ClientStoreRequest $...
method update (line 90) | public function update(Organization $organization, Client $client, Cli...
method destroy (line 110) | public function destroy(Organization $organization, Client $client): J...
FILE: app/Http/Controllers/Api/V1/Controller.php
class Controller (line 12) | class Controller extends \App\Http\Controllers\Controller
method __construct (line 14) | public function __construct(
method checkPermission (line 21) | protected function checkPermission(Organization $organization, string ...
method checkAnyPermission (line 33) | protected function checkAnyPermission(Organization $organization, arra...
method hasPermission (line 43) | protected function hasPermission(Organization $organization, string $p...
method canAccessPremiumFeatures (line 48) | protected function canAccessPremiumFeatures(Organization $organization...
FILE: app/Http/Controllers/Api/V1/CurrencyController.php
class CurrencyController (line 13) | class CurrencyController extends Controller
method index (line 22) | public function index(): JsonResponse
FILE: app/Http/Controllers/Api/V1/ExportController.php
class ExportController (line 15) | class ExportController extends Controller
method export (line 25) | public function export(Organization $organization, ExportService $expo...
FILE: app/Http/Controllers/Api/V1/ImportController.php
class ImportController (line 16) | class ImportController extends Controller
method index (line 27) | public function index(Organization $organization, ImporterProvider $im...
method import (line 58) | public function import(Organization $organization, ImportRequest $requ...
FILE: app/Http/Controllers/Api/V1/InvitationController.php
class InvitationController (line 20) | class InvitationController extends Controller
method checkPermission (line 22) | protected function checkPermission(Organization $organization, string ...
method index (line 39) | public function index(Organization $organization, InvitationIndexReque...
method store (line 59) | public function store(Organization $organization, InvitationStoreReque...
method resend (line 78) | public function resend(Organization $organization, OrganizationInvitat...
method destroy (line 94) | public function destroy(Organization $organization, OrganizationInvita...
FILE: app/Http/Controllers/Api/V1/MemberController.php
class MemberController (line 37) | class MemberController extends Controller
method checkPermission (line 39) | protected function checkPermission(Organization $organization, string ...
method index (line 56) | public function index(Organization $organization, MemberIndexRequest $...
method update (line 80) | public function update(Organization $organization, Member $member, Mem...
method destroy (line 106) | public function destroy(MemberDestroyRequest $request, Organization $o...
method makePlaceholder (line 125) | public function makePlaceholder(Organization $organization, Member $me...
method mergeInto (line 152) | public function mergeInto(Organization $organization, Member $member, ...
method invitePlaceholder (line 182) | public function invitePlaceholder(Organization $organization, Member $...
FILE: app/Http/Controllers/Api/V1/OrganizationController.php
class OrganizationController (line 14) | class OrganizationController extends Controller
method show (line 23) | public function show(Organization $organization): OrganizationResource
method update (line 39) | public function update(Organization $organization, OrganizationUpdateR...
FILE: app/Http/Controllers/Api/V1/ProjectController.php
class ProjectController (line 25) | class ProjectController extends Controller
method checkPermission (line 27) | protected function checkPermission(Organization $organization, string ...
method index (line 44) | public function index(Organization $organization, ProjectIndexRequest ...
method show (line 79) | public function show(Organization $organization, Project $project): Js...
method store (line 98) | public function store(Organization $organization, ProjectStoreRequest ...
method update (line 124) | public function update(Organization $organization, Project $project, P...
method destroy (line 168) | public function destroy(Organization $organization, Project $project):...
FILE: app/Http/Controllers/Api/V1/ProjectMemberController.php
class ProjectMemberController (line 23) | class ProjectMemberController extends Controller
method checkPermission (line 25) | protected function checkPermission(Organization $organization, string ...
method index (line 45) | public function index(Organization $organization, Project $project, Pr...
method store (line 64) | public function store(Organization $organization, Project $project, Pr...
method update (line 97) | public function update(Organization $organization, ProjectMember $proj...
method destroy (line 118) | public function destroy(Organization $organization, ProjectMember $pro...
FILE: app/Http/Controllers/Api/V1/Public/ReportController.php
class ReportController (line 19) | class ReportController extends Controller
method show (line 30) | public function show(Request $request, TimeEntryAggregationService $ti...
FILE: app/Http/Controllers/Api/V1/ReportController.php
class ReportController (line 22) | class ReportController extends Controller
method checkPermission (line 27) | protected function checkPermission(Organization $organization, string ...
method index (line 44) | public function index(Organization $organization, ReportIndexRequest $...
method show (line 63) | public function show(Organization $organization, Report $report): Deta...
method store (line 77) | public function store(Organization $organization, ReportStoreRequest $...
method update (line 134) | public function update(Organization $organization, Report $report, Rep...
method destroy (line 170) | public function destroy(Organization $organization, Report $report): J...
FILE: app/Http/Controllers/Api/V1/TagController.php
class TagController (line 19) | class TagController extends Controller
method checkPermission (line 21) | protected function checkPermission(Organization $organization, string ...
method index (line 38) | public function index(Organization $organization, TagIndexRequest $req...
method store (line 57) | public function store(Organization $organization, TagStoreRequest $req...
method update (line 76) | public function update(Organization $organization, Tag $tag, TagUpdate...
method destroy (line 93) | public function destroy(Organization $organization, Tag $tag): JsonRes...
FILE: app/Http/Controllers/Api/V1/TaskController.php
class TaskController (line 21) | class TaskController extends Controller
method checkPermission (line 23) | protected function checkPermission(Organization $organization, string ...
method checkScopedPermissionForProject (line 36) | private function checkScopedPermissionForProject(Organization $organiz...
method index (line 60) | public function index(Organization $organization, TaskIndexRequest $re...
method store (line 99) | public function store(Organization $organization, TaskStoreRequest $re...
method update (line 129) | public function update(Organization $organization, Task $task, TaskUpd...
method destroy (line 161) | public function destroy(Organization $organization, Task $task): JsonR...
FILE: app/Http/Controllers/Api/V1/TimeEntryController.php
class TimeEntryController (line 59) | class TimeEntryController extends Controller
method assertNoOverlap (line 61) | private function assertNoOverlap(Organization $organization, Member $m...
method checkPermission (line 98) | protected function checkPermission(Organization $organization, string ...
method index (line 118) | public function index(Organization $organization, TimeEntryIndexReques...
method getTimeEntriesQuery (line 183) | private function getTimeEntriesQuery(Organization $organization, TimeE...
method indexExport (line 220) | public function indexExport(Organization $organization, TimeEntryIndex...
method aggregate (line 369) | public function aggregate(Organization $organization, TimeEntryAggrega...
method aggregateExport (line 418) | public function aggregateExport(Organization $organization, TimeEntryA...
method getTimeEntriesAggregateQuery (line 549) | private function getTimeEntriesAggregateQuery(Organization $organizati...
method store (line 577) | public function store(Organization $organization, TimeEntryStoreReques...
method update (line 626) | public function update(Organization $organization, TimeEntry $timeEntr...
method updateMultiple (line 689) | public function updateMultiple(Organization $organization, TimeEntryUp...
method destroy (line 789) | public function destroy(Organization $organization, TimeEntry $timeEnt...
method destroyMultiple (line 820) | public function destroyMultiple(Organization $organization, TimeEntryD...
FILE: app/Http/Controllers/Api/V1/UserController.php
class UserController (line 10) | class UserController extends Controller
method me (line 21) | public function me(): UserResource
FILE: app/Http/Controllers/Api/V1/UserMembershipController.php
class UserMembershipController (line 12) | class UserMembershipController extends Controller
method myMemberships (line 25) | public function myMemberships(): JsonResource
FILE: app/Http/Controllers/Api/V1/UserTimeEntryController.php
class UserTimeEntryController (line 15) | class UserTimeEntryController extends Controller
method myActive (line 24) | public function myActive(): JsonResource
FILE: app/Http/Controllers/Controller.php
class Controller (line 17) | class Controller extends BaseController
method user (line 25) | protected function user(): User
method member (line 40) | protected function member(Organization $organization): Member
method currentOrganization (line 59) | protected function currentOrganization(): Organization
FILE: app/Http/Controllers/Web/Controller.php
class Controller (line 7) | abstract class Controller extends \App\Http\Controllers\Controller {}
FILE: app/Http/Controllers/Web/DashboardController.php
class DashboardController (line 14) | class DashboardController extends Controller
method dashboard (line 19) | public function dashboard(DashboardService $dashboardService, Permissi...
FILE: app/Http/Controllers/Web/HealthCheckController.php
class HealthCheckController (line 15) | class HealthCheckController extends Controller
method up (line 21) | public function up(): JsonResponse
method debug (line 32) | public function debug(Request $request): JsonResponse
FILE: app/Http/Controllers/Web/HomeController.php
class HomeController (line 10) | class HomeController extends Controller
method index (line 12) | public function index(): RedirectResponse
FILE: app/Http/Kernel.php
class Kernel (line 11) | class Kernel extends HttpKernel
FILE: app/Http/Middleware/Authenticate.php
class Authenticate (line 10) | class Authenticate extends Middleware
method redirectTo (line 15) | protected function redirectTo(Request $request): ?string
FILE: app/Http/Middleware/CheckOrganizationBlocked.php
class CheckOrganizationBlocked (line 14) | class CheckOrganizationBlocked
method handle (line 23) | public function handle(Request $request, Closure $next): Response
FILE: app/Http/Middleware/EncryptCookies.php
class EncryptCookies (line 9) | class EncryptCookies extends Middleware
FILE: app/Http/Middleware/EnsureEmailIsVerified.php
class EnsureEmailIsVerified (line 13) | class EnsureEmailIsVerified
method handle (line 18) | public function handle(Request $request, Closure $next, ?string $redir...
FILE: app/Http/Middleware/ForceHttps.php
class ForceHttps (line 12) | class ForceHttps
method handle (line 19) | public function handle(Request $request, Closure $next, string ...$gua...
FILE: app/Http/Middleware/ForceJsonResponse.php
class ForceJsonResponse (line 11) | class ForceJsonResponse
method handle (line 18) | public function handle(Request $request, Closure $next, string ...$gua...
FILE: app/Http/Middleware/HandleInertiaRequests.php
class HandleInertiaRequests (line 12) | class HandleInertiaRequests extends Middleware
method version (line 28) | public function version(Request $request): ?string
method share (line 40) | public function share(Request $request): array
FILE: app/Http/Middleware/PreventRequestsDuringMaintenance.php
class PreventRequestsDuringMaintenance (line 9) | class PreventRequestsDuringMaintenance extends Middleware
FILE: app/Http/Middleware/RedirectIfAuthenticated.php
class RedirectIfAuthenticated (line 13) | class RedirectIfAuthenticated
method handle (line 20) | public function handle(Request $request, Closure $next, string ...$gua...
FILE: app/Http/Middleware/ShareInertiaData.php
class ShareInertiaData (line 20) | class ShareInertiaData
method handle (line 25) | public function handle(Request $request, Closure $next): Response
FILE: app/Http/Middleware/TrimStrings.php
class TrimStrings (line 9) | class TrimStrings extends Middleware
FILE: app/Http/Middleware/TrustProxies.php
class TrustProxies (line 10) | class TrustProxies extends Middleware
FILE: app/Http/Middleware/ValidateSignature.php
class ValidateSignature (line 9) | class ValidateSignature extends Middleware
FILE: app/Http/Middleware/VerifyCsrfToken.php
class VerifyCsrfToken (line 9) | class VerifyCsrfToken extends Middleware
FILE: app/Http/Requests/V1/ApiToken/ApiTokenStoreRequest.php
class ApiTokenStoreRequest (line 9) | class ApiTokenStoreRequest extends BaseFormRequest
method rules (line 16) | public function rules(): array
method getName (line 28) | public function getName(): string
FILE: app/Http/Requests/V1/BaseFormRequest.php
class BaseFormRequest (line 9) | class BaseFormRequest extends FormRequest
method moneyRules (line 14) | protected function moneyRules(bool $bigInt = false): array
FILE: app/Http/Requests/V1/Client/ClientIndexRequest.php
class ClientIndexRequest (line 10) | class ClientIndexRequest extends BaseFormRequest
method rules (line 17) | public function rules(): array
method getFilterArchived (line 32) | public function getFilterArchived(): string
FILE: app/Http/Requests/V1/Client/ClientStoreRequest.php
class ClientStoreRequest (line 17) | class ClientStoreRequest extends BaseFormRequest
method rules (line 24) | public function rules(): array
FILE: app/Http/Requests/V1/Client/ClientUpdateRequest.php
class ClientUpdateRequest (line 18) | class ClientUpdateRequest extends BaseFormRequest
method rules (line 25) | public function rules(): array
method getIsArchived (line 45) | public function getIsArchived(): bool
FILE: app/Http/Requests/V1/Import/ImportRequest.php
class ImportRequest (line 10) | class ImportRequest extends BaseFormRequest
method rules (line 17) | public function rules(): array
FILE: app/Http/Requests/V1/Invitation/InvitationIndexRequest.php
class InvitationIndexRequest (line 14) | class InvitationIndexRequest extends BaseFormRequest
method rules (line 21) | public function rules(): array
FILE: app/Http/Requests/V1/Invitation/InvitationStoreRequest.php
class InvitationStoreRequest (line 16) | class InvitationStoreRequest extends BaseFormRequest
method rules (line 23) | public function rules(): array
method getRole (line 39) | public function getRole(): Role
method getEmail (line 44) | public function getEmail(): string
FILE: app/Http/Requests/V1/Member/MemberDestroyRequest.php
class MemberDestroyRequest (line 14) | class MemberDestroyRequest extends BaseFormRequest
method rules (line 21) | public function rules(): array
method getDeleteRelated (line 31) | public function getDeleteRelated(): bool
FILE: app/Http/Requests/V1/Member/MemberIndexRequest.php
class MemberIndexRequest (line 14) | class MemberIndexRequest extends BaseFormRequest
method rules (line 21) | public function rules(): array
FILE: app/Http/Requests/V1/Member/MemberMergeIntoRequest.php
class MemberMergeIntoRequest (line 17) | class MemberMergeIntoRequest extends BaseFormRequest
method rules (line 24) | public function rules(): array
method getMemberId (line 38) | public function getMemberId(): string
FILE: app/Http/Requests/V1/Member/MemberUpdateRequest.php
class MemberUpdateRequest (line 16) | class MemberUpdateRequest extends BaseFormRequest
method rules (line 23) | public function rules(): array
method getBillableRate (line 39) | public function getBillableRate(): ?int
method getRole (line 46) | public function getRole(): Role
FILE: app/Http/Requests/V1/Organization/OrganizationUpdateRequest.php
class OrganizationUpdateRequest (line 19) | class OrganizationUpdateRequest extends BaseFormRequest
method rules (line 26) | public function rules(): array
method getName (line 66) | public function getName(): ?string
method getNumberFormat (line 71) | public function getNumberFormat(): ?NumberFormat
method getCurrencyFormat (line 76) | public function getCurrencyFormat(): ?CurrencyFormat
method getDateFormat (line 81) | public function getDateFormat(): ?DateFormat
method getIntervalFormat (line 86) | public function getIntervalFormat(): ?IntervalFormat
method getTimeFormat (line 91) | public function getTimeFormat(): ?TimeFormat
method getBillableRate (line 96) | public function getBillableRate(): ?int
method getEmployeesCanSeeBillableRates (line 103) | public function getEmployeesCanSeeBillableRates(): ?bool
method getEmployeesCanManageTasks (line 108) | public function getEmployeesCanManageTasks(): ?bool
method getPreventOverlappingTimeEntries (line 113) | public function getPreventOverlappingTimeEntries(): ?bool
FILE: app/Http/Requests/V1/Project/ProjectIndexRequest.php
class ProjectIndexRequest (line 10) | class ProjectIndexRequest extends BaseFormRequest
method rules (line 17) | public function rules(): array
method getFilterArchived (line 32) | public function getFilterArchived(): string
FILE: app/Http/Requests/V1/Project/ProjectStoreRequest.php
class ProjectStoreRequest (line 21) | class ProjectStoreRequest extends BaseFormRequest
method rules (line 28) | public function rules(): array
method getIsPublic (line 87) | public function getIsPublic(): bool
method getBillableRate (line 92) | public function getBillableRate(): ?int
method getEstimatedTime (line 99) | public function getEstimatedTime(): ?int
FILE: app/Http/Requests/V1/Project/ProjectUpdateRequest.php
class ProjectUpdateRequest (line 22) | class ProjectUpdateRequest extends BaseFormRequest
method rules (line 29) | public function rules(): array
method getIsArchived (line 86) | public function getIsArchived(): bool
method getBillableRate (line 93) | public function getBillableRate(): ?int
method getEstimatedTime (line 100) | public function getEstimatedTime(): ?int
FILE: app/Http/Requests/V1/ProjectMember/ProjectMemberIndexRequest.php
class ProjectMemberIndexRequest (line 10) | class ProjectMemberIndexRequest extends BaseFormRequest
method rules (line 17) | public function rules(): array
FILE: app/Http/Requests/V1/ProjectMember/ProjectMemberStoreRequest.php
class ProjectMemberStoreRequest (line 17) | class ProjectMemberStoreRequest extends BaseFormRequest
method rules (line 24) | public function rules(): array
method getBillableRate (line 43) | public function getBillableRate(): ?int
FILE: app/Http/Requests/V1/ProjectMember/ProjectMemberUpdateRequest.php
class ProjectMemberUpdateRequest (line 14) | class ProjectMemberUpdateRequest extends BaseFormRequest
method rules (line 21) | public function rules(): array
method getBillableRate (line 33) | public function getBillableRate(): ?int
FILE: app/Http/Requests/V1/Report/ReportIndexRequest.php
class ReportIndexRequest (line 10) | class ReportIndexRequest extends BaseFormRequest
method rules (line 17) | public function rules(): array
FILE: app/Http/Requests/V1/Report/ReportStoreRequest.php
class ReportStoreRequest (line 23) | class ReportStoreRequest extends BaseFormRequest
method rules (line 30) | public function rules(): array
method getName (line 177) | public function getName(): string
method getDescription (line 182) | public function getDescription(): ?string
method getIsPublic (line 187) | public function getIsPublic(): bool
method getPublicUntil (line 192) | public function getPublicUntil(): ?Carbon
method getPropertyStart (line 199) | public function getPropertyStart(): Carbon
method getPropertyEnd (line 209) | public function getPropertyEnd(): Carbon
method getPropertyActive (line 219) | public function getPropertyActive(): ?bool
method getPropertyBillable (line 228) | public function getPropertyBillable(): ?bool
method getPropertyGroup (line 237) | public function getPropertyGroup(): TimeEntryAggregationType
method getPropertySubGroup (line 242) | public function getPropertySubGroup(): TimeEntryAggregationType
method getPropertyHistoryGroup (line 247) | public function getPropertyHistoryGroup(): TimeEntryAggregationTypeInt...
method getPropertyRoundingType (line 252) | public function getPropertyRoundingType(): ?TimeEntryRoundingType
method getPropertyRoundingMinutes (line 261) | public function getPropertyRoundingMinutes(): ?int
FILE: app/Http/Requests/V1/Report/ReportUpdateRequest.php
class ReportUpdateRequest (line 15) | class ReportUpdateRequest extends BaseFormRequest
method rules (line 22) | public function rules(): array
method getName (line 44) | public function getName(): string
method getDescription (line 49) | public function getDescription(): ?string
method getIsPublic (line 54) | public function getIsPublic(): bool
method getPublicUntil (line 59) | public function getPublicUntil(): ?Carbon
FILE: app/Http/Requests/V1/Tag/TagIndexRequest.php
class TagIndexRequest (line 10) | class TagIndexRequest extends BaseFormRequest
method rules (line 17) | public function rules(): array
FILE: app/Http/Requests/V1/Tag/TagStoreRequest.php
class TagStoreRequest (line 17) | class TagStoreRequest extends BaseFormRequest
method rules (line 24) | public function rules(): array
FILE: app/Http/Requests/V1/Tag/TagUpdateRequest.php
class TagUpdateRequest (line 18) | class TagUpdateRequest extends BaseFormRequest
method rules (line 25) | public function rules(): array
FILE: app/Http/Requests/V1/Task/TaskIndexRequest.php
class TaskIndexRequest (line 19) | class TaskIndexRequest extends BaseFormRequest
method rules (line 26) | public function rules(): array
method getFilterDone (line 53) | public function getFilterDone(): string
FILE: app/Http/Requests/V1/Task/TaskStoreRequest.php
class TaskStoreRequest (line 19) | class TaskStoreRequest extends BaseFormRequest
method rules (line 26) | public function rules(): array
method getEstimatedTime (line 56) | public function getEstimatedTime(): ?int
FILE: app/Http/Requests/V1/Task/TaskUpdateRequest.php
class TaskUpdateRequest (line 18) | class TaskUpdateRequest extends BaseFormRequest
method rules (line 25) | public function rules(): array
method getIsDone (line 51) | public function getIsDone(): bool
method getEstimatedTime (line 58) | public function getEstimatedTime(): ?int
FILE: app/Http/Requests/V1/TimeEntry/TimeEntryAggregateExportRequest.php
class TimeEntryAggregateExportRequest (line 29) | class TimeEntryAggregateExportRequest extends BaseFormRequest
method rules (line 36) | public function rules(): array
method getDebug (line 204) | public function getDebug(): bool
method getGroup (line 209) | public function getGroup(): TimeEntryAggregationType
method getSubGroup (line 214) | public function getSubGroup(): TimeEntryAggregationType
method getHistoryGroup (line 219) | public function getHistoryGroup(): TimeEntryAggregationType
method getStart (line 224) | public function getStart(): Carbon
method getEnd (line 234) | public function getEnd(): Carbon
method getFormatValue (line 244) | public function getFormatValue(): ExportFormat
method getRoundingType (line 249) | public function getRoundingType(): ?TimeEntryRoundingType
method getRoundingMinutes (line 258) | public function getRoundingMinutes(): ?int
FILE: app/Http/Requests/V1/TimeEntry/TimeEntryAggregateRequest.php
class TimeEntryAggregateRequest (line 27) | class TimeEntryAggregateRequest extends BaseFormRequest
method rules (line 34) | public function rules(): array
method getGroup (line 186) | public function getGroup(): ?TimeEntryAggregationType
method getSubGroup (line 191) | public function getSubGroup(): ?TimeEntryAggregationType
method getFillGapsInTimeGroups (line 196) | public function getFillGapsInTimeGroups(): bool
method getStart (line 201) | public function getStart(): ?Carbon
method getEnd (line 206) | public function getEnd(): ?Carbon
method getRoundingType (line 211) | public function getRoundingType(): ?TimeEntryRoundingType
method getRoundingMinutes (line 220) | public function getRoundingMinutes(): ?int
FILE: app/Http/Requests/V1/TimeEntry/TimeEntryDestroyMultipleRequest.php
class TimeEntryDestroyMultipleRequest (line 14) | class TimeEntryDestroyMultipleRequest extends BaseFormRequest
method rules (line 21) | public function rules(): array
FILE: app/Http/Requests/V1/TimeEntry/TimeEntryIndexExportRequest.php
class TimeEntryIndexExportRequest (line 25) | class TimeEntryIndexExportRequest extends TimeEntryIndexRequest
method rules (line 32) | public function rules(): array
method getDebug (line 183) | public function getDebug(): bool
method getStart (line 188) | public function getStart(): Carbon
method getEnd (line 198) | public function getEnd(): Carbon
method getOnlyFullDates (line 208) | public function getOnlyFullDates(): bool
method getFormatValue (line 213) | public function getFormatValue(): ExportFormat
method getRoundingType (line 218) | public function getRoundingType(): ?TimeEntryRoundingType
method getRoundingMinutes (line 227) | public function getRoundingMinutes(): ?int
FILE: app/Http/Requests/V1/TimeEntry/TimeEntryIndexRequest.php
class TimeEntryIndexRequest (line 25) | class TimeEntryIndexRequest extends BaseFormRequest
method rules (line 32) | public function rules(): array
method getOnlyFullDates (line 178) | public function getOnlyFullDates(): bool
method getLimit (line 183) | public function getLimit(): int
method getOffset (line 188) | public function getOffset(): int
method getRoundingType (line 193) | public function getRoundingType(): ?TimeEntryRoundingType
method getRoundingMinutes (line 202) | public function getRoundingMinutes(): ?int
FILE: app/Http/Requests/V1/TimeEntry/TimeEntryStoreRequest.php
class TimeEntryStoreRequest (line 22) | class TimeEntryStoreRequest extends BaseFormRequest
method rules (line 29) | public function rules(): array
FILE: app/Http/Requests/V1/TimeEntry/TimeEntryUpdateMultipleRequest.php
class TimeEntryUpdateMultipleRequest (line 22) | class TimeEntryUpdateMultipleRequest extends BaseFormRequest
method rules (line 29) | public function rules(): array
FILE: app/Http/Requests/V1/TimeEntry/TimeEntryUpdateRequest.php
class TimeEntryUpdateRequest (line 22) | class TimeEntryUpdateRequest extends BaseFormRequest
method rules (line 29) | public function rules(): array
FILE: app/Http/Resources/PaginatedResourceCollection.php
type PaginatedResourceCollection (line 7) | interface PaginatedResourceCollection {}
FILE: app/Http/Resources/V1/ApiToken/ApiTokenCollection.php
class ApiTokenCollection (line 9) | class ApiTokenCollection extends ResourceCollection
FILE: app/Http/Resources/V1/ApiToken/ApiTokenResource.php
class ApiTokenResource (line 14) | class ApiTokenResource extends BaseResource
method toArray (line 21) | public function toArray(Request $request): array
FILE: app/Http/Resources/V1/ApiToken/ApiTokenWithAccessTokenResource.php
class ApiTokenWithAccessTokenResource (line 14) | class ApiTokenWithAccessTokenResource extends BaseResource
method __construct (line 18) | public function __construct(Token $resource, string $accessToken)
method toArray (line 29) | public function toArray(Request $request): array
FILE: app/Http/Resources/V1/BaseResource.php
class BaseResource (line 10) | abstract class BaseResource extends JsonResource
method formatDateTime (line 12) | protected function formatDateTime(?Carbon $carbon): ?string
method formatDate (line 17) | protected function formatDate(?Carbon $carbon): ?string
FILE: app/Http/Resources/V1/Client/ClientCollection.php
class ClientCollection (line 10) | class ClientCollection extends ResourceCollection implements PaginatedRe...
FILE: app/Http/Resources/V1/Client/ClientResource.php
class ClientResource (line 14) | class ClientResource extends BaseResource
method toArray (line 21) | public function toArray(Request $request): array
FILE: app/Http/Resources/V1/Invitation/InvitationCollection.php
class InvitationCollection (line 10) | class InvitationCollection extends ResourceCollection implements Paginat...
FILE: app/Http/Resources/V1/Invitation/InvitationResource.php
class InvitationResource (line 14) | class InvitationResource extends BaseResource
method toArray (line 21) | public function toArray(Request $request): array
FILE: app/Http/Resources/V1/Member/MemberCollection.php
class MemberCollection (line 10) | class MemberCollection extends ResourceCollection implements PaginatedRe...
FILE: app/Http/Resources/V1/Member/MemberResource.php
class MemberResource (line 15) | class MemberResource extends BaseResource
method toArray (line 22) | public function toArray(Request $request): array
FILE: app/Http/Resources/V1/Member/PersonalMembershipCollection.php
class PersonalMembershipCollection (line 10) | class PersonalMembershipCollection extends ResourceCollection implements...
FILE: app/Http/Resources/V1/Member/PersonalMembershipResource.php
class PersonalMembershipResource (line 14) | class PersonalMembershipResource extends BaseResource
method toArray (line 21) | public function toArray(Request $request): array
FILE: app/Http/Resources/V1/Organization/OrganizationResource.php
class OrganizationResource (line 20) | class OrganizationResource extends BaseResource
method __construct (line 29) | public function __construct(Organization $resource, bool $showBillable...
method toArray (line 41) | public function toArray(Request $request): array
FILE: app/Http/Resources/V1/Project/ProjectCollection.php
class ProjectCollection (line 12) | class ProjectCollection extends ResourceCollection implements PaginatedR...
method __construct (line 16) | public function __construct($resource, bool $showBillableRates)
method collects (line 22) | protected function collects(): ?string
method toArray (line 32) | public function toArray(Request $request): array
FILE: app/Http/Resources/V1/Project/ProjectResource.php
class ProjectResource (line 14) | class ProjectResource extends BaseResource
method __construct (line 18) | public function __construct(Project $resource, bool $showBillableRate)
method toArray (line 30) | public function toArray(Request $request): array
FILE: app/Http/Resources/V1/ProjectMember/ProjectMemberCollection.php
class ProjectMemberCollection (line 10) | class ProjectMemberCollection extends ResourceCollection implements Pagi...
FILE: app/Http/Resources/V1/ProjectMember/ProjectMemberResource.php
class ProjectMemberResource (line 14) | class ProjectMemberResource extends BaseResource
method toArray (line 21) | public function toArray(Request $request): array
FILE: app/Http/Resources/V1/Report/DetailedReportResource.php
class DetailedReportResource (line 14) | class DetailedReportResource extends BaseResource
method toArray (line 21) | public function toArray(Request $request): array
FILE: app/Http/Resources/V1/Report/DetailedWithDataReportResource.php
class DetailedWithDataReportResource (line 43) | class DetailedWithDataReportResource extends BaseResource
method __construct (line 59) | public function __construct(Report $resource, array $data, array $hist...
method toArray (line 71) | public function toArray(Request $request): array
FILE: app/Http/Resources/V1/Report/ReportCollection.php
class ReportCollection (line 10) | class ReportCollection extends ResourceCollection implements PaginatedRe...
FILE: app/Http/Resources/V1/Report/ReportResource.php
class ReportResource (line 14) | class ReportResource extends BaseResource
method toArray (line 21) | public function toArray(Request $request): array
FILE: app/Http/Resources/V1/Tag/TagCollection.php
class TagCollection (line 10) | class TagCollection extends ResourceCollection implements PaginatedResou...
FILE: app/Http/Resources/V1/Tag/TagResource.php
class TagResource (line 14) | class TagResource extends BaseResource
method toArray (line 21) | public function toArray(Request $request): array
FILE: app/Http/Resources/V1/Task/TaskCollection.php
class TaskCollection (line 10) | class TaskCollection extends ResourceCollection implements PaginatedReso...
FILE: app/Http/Resources/V1/Task/TaskResource.php
class TaskResource (line 15) | class TaskResource extends BaseResource
method toArray (line 22) | public function toArray(Request $request): array
FILE: app/Http/Resources/V1/TimeEntry/TimeEntryCollection.php
class TimeEntryCollection (line 10) | class TimeEntryCollection extends ResourceCollection implements Paginate...
FILE: app/Http/Resources/V1/TimeEntry/TimeEntryResource.php
class TimeEntryResource (line 14) | class TimeEntryResource extends BaseResource
method toArray (line 21) | public function toArray(Request $request): array
FILE: app/Http/Resources/V1/User/UserResource.php
class UserResource (line 15) | class UserResource extends BaseResource
method toArray (line 22) | public function toArray(Request $request): array
FILE: app/Jobs/RecalculateSpentTimeForProject.php
class RecalculateSpentTimeForProject (line 16) | class RecalculateSpentTimeForProject implements ShouldDispatchAfterCommi...
method __construct (line 28) | public function __construct(Project $project)
method handle (line 38) | public function handle(): void
FILE: app/Jobs/RecalculateSpentTimeForTask.php
class RecalculateSpentTimeForTask (line 16) | class RecalculateSpentTimeForTask implements ShouldDispatchAfterCommit, ...
method __construct (line 28) | public function __construct(Task $task)
method handle (line 38) | public function handle(): void
FILE: app/Jobs/Test/TestJob.php
class TestJob (line 16) | class TestJob implements ShouldQueue
method __construct (line 32) | public function __construct(User $user, string $message, bool $fail = ...
method handle (line 44) | public function handle(): void
FILE: app/Listeners/RemovePlaceholder.php
class RemovePlaceholder (line 13) | class RemovePlaceholder
method handle (line 18) | public function handle(TeamMemberAdded $event): void
FILE: app/Mail/AuthApiTokenExpirationReminderMail.php
class AuthApiTokenExpirationReminderMail (line 14) | class AuthApiTokenExpirationReminderMail extends Mailable
method __construct (line 27) | public function __construct(Token $token, User $user)
method build (line 36) | public function build(): self
FILE: app/Mail/AuthApiTokenExpiredMail.php
class AuthApiTokenExpiredMail (line 14) | class AuthApiTokenExpiredMail extends Mailable
method __construct (line 27) | public function __construct(Token $token, User $user)
method build (line 36) | public function build(): self
FILE: app/Mail/OrganizationInvitationMail.php
class OrganizationInvitationMail (line 13) | class OrganizationInvitationMail extends Mailable
method __construct (line 24) | public function __construct(OrganizationInvitation $invitation)
method build (line 32) | public function build(): self
FILE: app/Mail/TimeEntryStillRunningMail.php
class TimeEntryStillRunningMail (line 14) | class TimeEntryStillRunningMail extends Mailable
method __construct (line 27) | public function __construct(TimeEntry $timeEntry, User $user)
method build (line 36) | public function build(): self
FILE: app/Models/Audit.php
class Audit (line 30) | class Audit extends PackageAuditModel
FILE: app/Models/Client.php
class Client (line 31) | class Client extends Model implements AuditableContract
method organization (line 53) | public function organization(): BelongsTo
method projects (line 61) | public function projects(): HasMany
method scopeVisibleByEmployee (line 70) | public function scopeVisibleByEmployee(Builder $builder, User $user): ...
method isArchived (line 81) | protected function isArchived(): Attribute
FILE: app/Models/Concerns/CustomAuditable.php
type CustomAuditable (line 9) | trait CustomAuditable
method disableAuditing (line 18) | public function disableAuditing(): void
FILE: app/Models/Concerns/HasUuids.php
type HasUuids (line 9) | trait HasUuids
method newUniqueId (line 16) | public function newUniqueId(): string
FILE: app/Models/FailedJob.php
class FailedJob (line 18) | class FailedJob extends Model
FILE: app/Models/Member.php
class Member (line 33) | class Member extends JetstreamMembership implements AuditableContract
method user (line 52) | public function user(): BelongsTo
method organization (line 60) | public function organization(): BelongsTo
method timeEntries (line 68) | public function timeEntries(): HasMany
method projectMembers (line 76) | public function projectMembers(): HasMany
FILE: app/Models/Organization.php
class Organization (line 55) | class Organization extends JetstreamTeam implements AuditableContract
method allRealUsers (line 117) | public function allRealUsers(): Collection
method hasRealUserWithEmail (line 122) | public function hasRealUserWithEmail(string $email): bool
method users (line 134) | public function users(): BelongsToMany
method owner (line 151) | public function owner(): BelongsTo
method members (line 159) | public function members(): HasMany
method realUsers (line 167) | public function realUsers(): BelongsToMany
method findOrFail (line 179) | public function findOrFail(string $id, array $columns = ['*']): \Larav...
FILE: app/Models/OrganizationInvitation.php
class OrganizationInvitation (line 27) | class OrganizationInvitation extends JetstreamTeamInvitation implements ...
method organization (line 58) | public function organization(): BelongsTo
method team (line 68) | public function team(): BelongsTo
FILE: app/Models/Passport/AuthCode.php
class AuthCode (line 20) | class AuthCode extends PassportAuthCode
method user (line 25) | public function user(): BelongsTo
FILE: app/Models/Passport/Client.php
class Client (line 26) | class Client extends PassportClient
method newFactory (line 36) | protected static function newFactory(): Factory
FILE: app/Models/Passport/RefreshToken.php
class RefreshToken (line 9) | class RefreshToken extends PassportRefreshToken {}
FILE: app/Models/Passport/Token.php
class Token (line 32) | class Token extends PassportToken
method client (line 43) | public function client(): BelongsTo
method user (line 56) | public function user(): BelongsTo
method casts (line 66) | protected function casts(): array
method scopeIsApiToken (line 81) | public function scopeIsApiToken(Builder $query, bool $isApiToken = tru...
FILE: app/Models/Project.php
class Project (line 45) | class Project extends Model implements AuditableContract
method getSpentTimeComputed (line 96) | public function getSpentTimeComputed(): ?int
method scopeComputedAttributesGenerate (line 118) | public function scopeComputedAttributesGenerate(Builder $builder, arra...
method scopeComputedAttributesValidate (line 134) | public function scopeComputedAttributesValidate(Builder $builder, arra...
method organization (line 142) | public function organization(): BelongsTo
method client (line 150) | public function client(): BelongsTo
method members (line 158) | public function members(): HasMany
method tasks (line 166) | public function tasks(): HasMany
method timeEntries (line 174) | public function timeEntries(): HasMany
method scopeVisibleByEmployee (line 182) | public function scopeVisibleByEmployee(Builder $builder, User $user): ...
method isArchived (line 195) | protected function isArchived(): Attribute
FILE: app/Models/ProjectMember.php
class ProjectMember (line 32) | class ProjectMember extends Model implements AuditableContract
method project (line 53) | public function project(): BelongsTo
method user (line 63) | public function user(): BelongsTo
method member (line 71) | public function member(): BelongsTo
method scopeWhereBelongsToOrganization (line 79) | public function scopeWhereBelongsToOrganization(Builder $builder, Orga...
FILE: app/Models/Report.php
class Report (line 30) | class Report extends Model
method getShareableLink (line 48) | public function getShareableLink(): ?string
method organization (line 60) | public function organization(): BelongsTo
FILE: app/Models/Tag.php
class Tag (line 30) | class Tag extends Model implements AuditableContract
method organization (line 52) | public function organization(): BelongsTo
method timeEntries (line 62) | public function timeEntries(): HasManyJson
FILE: app/Models/Task.php
class Task (line 39) | class Task extends Model implements AuditableContract
method getSpentTimeComputed (line 79) | public function getSpentTimeComputed(): ?int
method scopeComputedAttributesGenerate (line 101) | public function scopeComputedAttributesGenerate(Builder $builder, arra...
method scopeComputedAttributesValidate (line 117) | public function scopeComputedAttributesValidate(Builder $builder, arra...
method project (line 125) | public function project(): BelongsTo
method organization (line 133) | public function organization(): BelongsTo
method timeEntries (line 141) | public function timeEntries(): HasMany
method scopeVisibleByEmployee (line 150) | public function scopeVisibleByEmployee(Builder $builder, User $user): ...
method isDone (line 161) | public function isDone(): Attribute
FILE: app/Models/TimeEntry.php
class TimeEntry (line 53) | class TimeEntry extends Model implements AuditableContract
method getBillableRateComputed (line 120) | public function getBillableRateComputed(): ?int
method getClientIdComputed (line 125) | public function getClientIdComputed(): ?string
method scopeComputedAttributesGenerate (line 137) | public function scopeComputedAttributesGenerate(Builder $builder, arra...
method scopeComputedAttributesValidate (line 158) | public function scopeComputedAttributesValidate(Builder $builder, arra...
method getDuration (line 163) | public function getDuration(): ?CarbonInterval
method scopeHasTag (line 171) | public function scopeHasTag(Builder $builder, Tag $tag): void
method user (line 179) | public function user(): BelongsTo
method member (line 187) | public function member(): BelongsTo
method organization (line 195) | public function organization(): BelongsTo
method project (line 203) | public function project(): BelongsTo
method task (line 211) | public function task(): BelongsTo
method client (line 221) | public function client(): BelongsTo
method tagsRelation (line 231) | public function tagsRelation(): BelongsToJson
FILE: app/Models/User.php
class User (line 63) | class User extends Authenticatable implements AuditableContract, Filamen...
method profilePhotoUrl (line 128) | protected function profilePhotoUrl(): Attribute
method canAccessPanel (line 137) | public function canAccessPanel(Panel $panel): bool
method canBeImpersonated (line 142) | public function canBeImpersonated(): bool
method organizations (line 150) | public function organizations(): BelongsToMany
method timeEntries (line 165) | public function timeEntries(): HasMany
method currentOrganization (line 173) | public function currentOrganization(): BelongsTo
method projectMembers (line 181) | public function projectMembers(): HasMany
method accessTokens (line 189) | public function accessTokens(): HasMany
method authCodes (line 197) | public function authCodes(): HasMany
method scopeActive (line 205) | public function scopeActive(Builder $builder): void
method scopeBelongsToOrganization (line 214) | public function scopeBelongsToOrganization(Builder $builder, Organizat...
FILE: app/Policies/OrganizationPolicy.php
class OrganizationPolicy (line 13) | class OrganizationPolicy
method viewAny (line 20) | public function viewAny(User $user): bool
method view (line 32) | public function view(User $user, Organization $organization): bool
method create (line 44) | public function create(User $user): bool
method update (line 56) | public function update(User $user, Organization $organization): bool
method addTeamMember (line 68) | public function addTeamMember(User $user, Organization $organization):...
method updateTeamMember (line 80) | public function updateTeamMember(User $user, Organization $organizatio...
method removeTeamMember (line 93) | public function removeTeamMember(User $user, Organization $organizatio...
method delete (line 106) | public function delete(User $user, Organization $organization): bool
FILE: app/Providers/AppServiceProvider.php
class AppServiceProvider (line 35) | class AppServiceProvider extends ServiceProvider
method register (line 40) | public function register(): void
method boot (line 48) | public function boot(): void
FILE: app/Providers/AuthServiceProvider.php
class AuthServiceProvider (line 17) | class AuthServiceProvider extends ServiceProvider
method boot (line 31) | public function boot(): void
FILE: app/Providers/EventServiceProvider.php
class EventServiceProvider (line 13) | class EventServiceProvider extends ServiceProvider
method boot (line 32) | public function boot(): void
method shouldDiscoverEvents (line 40) | public function shouldDiscoverEvents(): bool
FILE: app/Providers/Filament/AdminPanelProvider.php
class AdminPanelProvider (line 31) | class AdminPanelProvider extends PanelProvider
method panel (line 33) | public function panel(Panel $panel): Panel
FILE: app/Providers/FortifyServiceProvider.php
class FortifyServiceProvider (line 24) | class FortifyServiceProvider extends ServiceProvider
method register (line 29) | public function register(): void
method boot (line 37) | public function boot(): void
FILE: app/Providers/JetstreamServiceProvider.php
class JetstreamServiceProvider (line 34) | class JetstreamServiceProvider extends ServiceProvider
method register (line 39) | public function register(): void
method boot (line 47) | public function boot(): void
method configurePermissions (line 78) | protected function configurePermissions(): void
FILE: app/Providers/RouteServiceProvider.php
class RouteServiceProvider (line 14) | class RouteServiceProvider extends ServiceProvider
method boot (line 28) | public function boot(): void
FILE: app/Providers/TelescopeServiceProvider.php
class TelescopeServiceProvider (line 13) | class TelescopeServiceProvider extends TelescopeApplicationServiceProvider
method register (line 18) | public function register(): void
method hideSensitiveRequestDetails (line 40) | protected function hideSensitiveRequestDetails(): void
method gate (line 60) | protected function gate(): void
FILE: app/Rules/ColorRule.php
class ColorRule (line 12) | class ColorRule implements ValidationRule
method validate (line 19) | public function validate(string $attribute, mixed $value, Closure $fai...
FILE: app/Rules/CurrencyRule.php
class CurrencyRule (line 12) | class CurrencyRule implements ValidationRule
method validate (line 19) | public function validate(string $attribute, mixed $value, Closure $fai...
FILE: app/Service/ApiService.php
class ApiService (line 19) | class ApiService
method checkForUpdate (line 23) | public function checkForUpdate(): ?string
method telemetry (line 54) | public function telemetry(): bool
FILE: app/Service/BillableRateService.php
class BillableRateService (line 14) | class BillableRateService
method updateTimeEntriesBillableRateForProjectMember (line 16) | public function updateTimeEntriesBillableRateForProjectMember(ProjectM...
method updateTimeEntriesBillableRateForProject (line 25) | public function updateTimeEntriesBillableRateForProject(Project $proje...
method updateTimeEntriesBillableRateForMember (line 42) | public function updateTimeEntriesBillableRateForMember(Member $member)...
method updateTimeEntriesBillableRateForOrganization (line 60) | public function updateTimeEntriesBillableRateForOrganization(Organizat...
method getBillableRateForTimeEntryWithGivenRelations (line 81) | public function getBillableRateForTimeEntryWithGivenRelations(TimeEntr...
method getBillableRateForTimeEntry (line 102) | public function getBillableRateForTimeEntry(TimeEntry $timeEntry): ?int
FILE: app/Service/BillingContract.php
class BillingContract (line 15) | class BillingContract
method hasSubscription (line 23) | public function hasSubscription(Organization $organization): bool
method hasTrial (line 32) | public function hasTrial(Organization $organization): bool
method getTrialUntil (line 41) | public function getTrialUntil(Organization $organization): ?Carbon
method isBlocked (line 53) | public function isBlocked(Organization $organization): bool
FILE: app/Service/ColorService.php
class ColorService (line 7) | class ColorService
method isBuiltInColor (line 36) | public function isBuiltInColor(string $color): bool
method getRandomColor (line 41) | public function getRandomColor(?string $seed = null): string
method isValid (line 50) | public function isValid(string $color): bool
FILE: app/Service/CurrencyService.php
class CurrencyService (line 10) | class CurrencyService
method getCurrencySymbolForMoney (line 365) | public function getCurrencySymbolForMoney(Money $money): string
method getCurrencySymbol (line 370) | public function getCurrencySymbol(string $currencyCode): string
method getRandomCurrencyCode (line 379) | public function getRandomCurrencyCode(): string
FILE: app/Service/DashboardService.php
class DashboardService (line 19) | class DashboardService
method __construct (line 23) | public function __construct(TimezoneService $timezoneService)
method lastDays (line 31) | private function lastDays(int $days, CarbonTimeZone $timeZone): Collec...
method lastDaysSplitInWindows (line 46) | private function lastDaysSplitInWindows(int $days, CarbonTimeZone $tim...
method daysOfThisWeek (line 80) | private function daysOfThisWeek(CarbonTimeZone $timeZone, Weekday $sta...
method constrainDateByPossibleDates (line 98) | private function constrainDateByPossibleDates(Builder $builder, Collec...
method constrainDateByCurrentWeek (line 123) | private function constrainDateByCurrentWeek(Builder $builder, CarbonTi...
method getDailyTrackedHours (line 138) | public function getDailyTrackedHours(User $user, Organization $organiz...
method getWeeklyHistory (line 181) | public function getWeeklyHistory(User $user, Organization $organizatio...
method totalWeeklyTime (line 217) | public function totalWeeklyTime(User $user, Organization $organization...
method totalWeeklyBillableTime (line 234) | public function totalWeeklyBillableTime(User $user, Organization $orga...
method totalWeeklyBillableAmount (line 255) | public function totalWeeklyBillableAmount(User $user, Organization $or...
method weeklyProjectOverview (line 285) | public function weeklyProjectOverview(User $user, Organization $organi...
method latestTeamActivity (line 345) | public function latestTeamActivity(Organization $organization): array
method latestTasks (line 383) | public function latestTasks(User $user, Organization $organization): a...
method lastSevenDays (line 423) | public function lastSevenDays(User $user, Organization $organization):...
FILE: app/Service/DeletionService.php
class DeletionService (line 24) | class DeletionService
method __construct (line 30) | public function __construct(UserService $userService, MemberService $m...
method deleteOrganization (line 36) | public function deleteOrganization(Organization $organization, bool $i...
method deleteUser (line 133) | public function deleteUser(User $user, bool $inTransaction = true): void
FILE: app/Service/Dto/ReportPropertiesDto.php
class ReportPropertiesDto (line 19) | class ReportPropertiesDto implements Castable
method castUsing (line 74) | public static function castUsing(array $arguments): CastsAttributes
method idArrayToCollection (line 171) | public static function idArrayToCollection(array $ids): Collection
method setMemberIds (line 190) | public function setMemberIds(?array $memberIds): void
method setClientIds (line 198) | public function setClientIds(?array $clientIds): void
method setProjectIds (line 206) | public function setProjectIds(?array $projectIds): void
method setTagIds (line 214) | public function setTagIds(?array $tagIds): void
method setTaskIds (line 222) | public function setTaskIds(?array $taskIds): void
FILE: app/Service/Export/ExportException.php
class ExportException (line 9) | class ExportException extends ApiException
FILE: app/Service/Export/ExportService.php
class ExportService (line 30) | class ExportService
method export (line 37) | public function export(Organization $organization): string
FILE: app/Service/Import/ImportDatabaseHelper.php
class ImportDatabaseHelper (line 16) | class ImportDatabaseHelper
method __construct (line 68) | public function __construct(string $model, array $identifiers, bool $a...
method getModelInstance (line 83) | private function getModelInstance(): Builder
method createEntity (line 92) | private function createEntity(array $identifierData, array $createValu...
method getHash (line 132) | private function getHash(array $data): string
method getKey (line 148) | public function getKey(array $identifierData, array $createValues = []...
method getModelById (line 174) | public function getModelById(string $id): ?Model
method getCachedModels (line 194) | public function getCachedModels(): array
method getModel (line 207) | public function getModel(array $identifierData): ?Model
method validateIdentifierData (line 229) | private function validateIdentifierData(array $identifierData): void
method getKeyByExternalIdentifier (line 236) | public function getKeyByExternalIdentifier(string $externalIdentifier)...
method getExternalIds (line 249) | public function getExternalIds(): array
method checkMap (line 255) | private function checkMap(): void
method getCreatedCount (line 280) | public function getCreatedCount(): int
FILE: app/Service/Import/ImportService.php
class ImportService (line 18) | class ImportService
method import (line 23) | public function import(Organization $organization, string $importerTyp...
FILE: app/Service/Import/Importers/ClockifyProjectsImporter.php
class ClockifyProjectsImporter (line 12) | class ClockifyProjectsImporter extends DefaultImporter
method importData (line 17) | #[\Override]
method validateHeader (line 76) | private function validateHeader(array $header): void
method getBillableRateKey (line 96) | private function getBillableRateKey(array $header): ?string
method getName (line 109) | #[\Override]
method getDescription (line 115) | #[\Override]
FILE: app/Service/Import/Importers/ClockifyTimeEntriesImporter.php
class ClockifyTimeEntriesImporter (line 18) | class ClockifyTimeEntriesImporter extends DefaultImporter
method getTags (line 25) | private function getTags(string $tags): array
method importData (line 46) | #[\Override]
method validateHeader (line 211) | private function validateHeader(array $header): void
method getName (line 235) | #[\Override]
method getDescription (line 241) | #[\Override]
FILE: app/Service/Import/Importers/DefaultImporter.php
class DefaultImporter (line 22) | abstract class DefaultImporter implements ImporterContract
method init (line 74) | public function init(Organization $organization): void
method getReport (line 184) | #[\Override]
FILE: app/Service/Import/Importers/GenericProjectsImporter.php
class GenericProjectsImporter (line 15) | class GenericProjectsImporter extends DefaultImporter
method importData (line 27) | #[Override]
method validateHeader (line 85) | private function validateHeader(array $header): void
method getName (line 94) | #[Override]
method getDescription (line 100) | #[Override]
FILE: app/Service/Import/Importers/GenericTimeEntriesImporter.php
class GenericTimeEntriesImporter (line 18) | class GenericTimeEntriesImporter extends DefaultImporter
method getTags (line 41) | private function getTags(string $tags): array
method importData (line 62) | #[\Override]
method validateHeader (line 188) | private function validateHeader(array $header): void
method getName (line 197) | #[\Override]
method getDescription (line 203) | #[\Override]
FILE: app/Service/Import/Importers/HarvestClientsImporter.php
class HarvestClientsImporter (line 11) | class HarvestClientsImporter extends DefaultImporter
method importData (line 23) | #[\Override]
method validateHeader (line 56) | private function validateHeader(array $header): void
method getName (line 65) | #[\Override]
method getDescription (line 71) | #[\Override]
FILE: app/Service/Import/Importers/HarvestProjectsImporter.php
class HarvestProjectsImporter (line 12) | class HarvestProjectsImporter extends DefaultImporter
method importData (line 27) | #[\Override]
method validateHeader (line 87) | private function validateHeader(array $header): void
method getName (line 96) | #[\Override]
method getDescription (line 102) | #[\Override]
FILE: app/Service/Import/Importers/HarvestTimeEntriesImporter.php
class HarvestTimeEntriesImporter (line 19) | class HarvestTimeEntriesImporter extends DefaultImporter
method importData (line 39) | #[Override]
method validateHeader (line 171) | private function validateHeader(array $header): void
method getName (line 180) | #[Override]
method getDescription (line 186) | #[Override]
FILE: app/Service/Import/Importers/ImportException.php
class ImportException (line 7) | class ImportException extends \Exception {}
FILE: app/Service/Import/Importers/ImporterContract.php
type ImporterContract (line 9) | interface ImporterContract
method init (line 11) | public function init(Organization $organization): void;
method importData (line 13) | public function importData(string $data, string $timezone): void;
method getReport (line 15) | public function getReport(): ReportDto;
method getName (line 17) | public function getName(): string;
method getDescription (line 19) | public function getDescription(): string;
FILE: app/Service/Import/Importers/ImporterProvider.php
class ImporterProvider (line 7) | class ImporterProvider
method registerImporter (line 28) | public function registerImporter(string $type, string $importer): void
method getImporterKeys (line 36) | public function getImporterKeys(): array
method getImporters (line 44) | public function getImporters(): array
method getImporter (line 49) | public function getImporter(string $type): ImporterContract
FILE: app/Service/Import/Importers/ReportDto.php
class ReportDto (line 7) | class ReportDto
method __construct (line 21) | public function __construct(int $clientsCreated, int $projectsCreated,...
method toArray (line 53) | public function toArray(): array
FILE: app/Service/Import/Importers/SolidtimeImporter.php
class SolidtimeImporter (line 20) | class SolidtimeImporter extends DefaultImporter
method importData (line 30) | #[Override]
method getTags (line 329) | private function getTags(string $tags): array
method getName (line 350) | #[Override]
method getDescription (line 356) | #[Override]
FILE: app/Service/Import/Importers/TogglDataImporter.php
class TogglDataImporter (line 18) | class TogglDataImporter extends DefaultImporter
method importData (line 23) | #[Override]
method getName (line 212) | #[Override]
method getDescription (line 218) | #[Override]
FILE: app/Service/Import/Importers/TogglTimeEntriesImporter.php
class TogglTimeEntriesImporter (line 18) | class TogglTimeEntriesImporter extends DefaultImporter
method getTags (line 25) | private function getTags(string $tags): array
method importData (line 46) | #[\Override]
method validateHeader (line 172) | private function validateHeader(array $header): void
method getName (line 195) | #[\Override]
method getDescription (line 201) | #[\Override]
FILE: app/Service/IntervalService.php
class IntervalService (line 9) | class IntervalService
method format (line 11) | public function format(CarbonInterval $interval): string
FILE: app/Service/InvitationService.php
class InvitationService (line 17) | class InvitationService
method inviteUser (line 22) | public function inviteUser(Organization $organization, string $email, ...
FILE: app/Service/IpLookup/IpLookupResponseDto.php
class IpLookupResponseDto (line 9) | class IpLookupResponseDto
method __construct (line 17) | public function __construct(?string $timezone, ?Weekday $startOfWeek, ...
FILE: app/Service/IpLookup/IpLookupServiceContract.php
type IpLookupServiceContract (line 7) | interface IpLookupServiceContract
method lookup (line 9) | public function lookup(string $ip): ?IpLookupResponseDto;
FILE: app/Service/IpLookup/NoIpLookupService.php
class NoIpLookupService (line 7) | class NoIpLookupService implements IpLookupServiceContract
method lookup (line 9) | public function lookup(string $ip): ?IpLookupResponseDto
FILE: app/Service/LocalizationService.php
class LocalizationService (line 18) | class LocalizationService
method __construct (line 30) | public function __construct(CurrencyFormat $currencyFormat, DateFormat...
method forOrganization (line 39) | public static function forOrganization(Organization $organization): self
method formatNumber (line 50) | public function formatNumber(BigDecimal|float $number): string
method formatNumberWithoutTrailingZeros (line 67) | public function formatNumberWithoutTrailingZeros(BigDecimal|float $num...
method formatInterval (line 78) | public function formatInterval(CarbonInterval $interval): string
method formatCurrency (line 99) | public function formatCurrency(Money $money): string
method formatTime (line 117) | public function formatTime(CarbonInterface $time): string
method formatDate (line 126) | public function formatDate(CarbonInterface $date): string
method setDateFormat (line 131) | public function setDateFormat(DateFormat $dateFormat): void
method setCurrencyFormat (line 136) | public function setCurrencyFormat(CurrencyFormat $currencyFormat): void
method setIntervalFormat (line 141) | public function setIntervalFormat(IntervalFormat $intervalFormat): void
method setTimeFormat (line 146) | public function setTimeFormat(TimeFormat $timeFormat): void
method setNumberFormat (line 151) | public function setNumberFormat(NumberFormat $numberFormat): void
FILE: app/Service/MemberService.php
class MemberService (line 27) | class MemberService
method __construct (line 31) | public function __construct(UserService $userService)
method addMember (line 36) | public function addMember(User $user, Organization $organization, Role...
method removeMember (line 64) | public function removeMember(Member $member, Organization $organizatio...
method changeRole (line 108) | public function changeRole(Member $member, Organization $organization,...
method assignOrganizationEntitiesToDifferentMember (line 131) | public function assignOrganizationEntitiesToDifferentMember(Organizati...
method changeOwnership (line 168) | public function changeOwnership(Organization $organization, Member $ne...
method makeMemberToPlaceholder (line 189) | public function makeMemberToPlaceholder(Member $member, bool $makeSure...
FILE: app/Service/OrganizationInvitationService.php
class OrganizationInvitationService (line 11) | class OrganizationInvitationService
method resend (line 13) | public function resend(OrganizationInvitation $invitation): void
FILE: app/Service/OrganizationService.php
class OrganizationService (line 16) | class OrganizationService
method createOrganization (line 18) | public function createOrganization(
FILE: app/Service/PermissionStore.php
class PermissionStore (line 13) | class PermissionStore
method clear (line 20) | public function clear(): void
method has (line 25) | public function has(Organization $organization, string $permission): bool
method userHas (line 36) | public function userHas(Organization $organization, User $user, string...
method getPermissionsByUser (line 55) | private function getPermissionsByUser(Organization $organization, User...
method getPermissions (line 92) | public function getPermissions(Organization $organization): array
FILE: app/Service/ReportExport/CsvExport.php
class CsvExport (line 19) | abstract class CsvExport
method __construct (line 44) | public function __construct(string $disk, string $folderPath, string $...
method mapRow (line 58) | abstract public function mapRow(Model $model): array;
method export (line 65) | public function export(): void
method convertRow (line 91) | private function convertRow(array $data): array
method validateRow (line 112) | private function validateRow(array $row): void
FILE: app/Service/ReportExport/TimeEntriesDetailedCsvExport.php
class TimeEntriesDetailedCsvExport (line 15) | class TimeEntriesDetailedCsvExport extends CsvExport
method __construct (line 35) | public function __construct(string $disk, string $folderPath, string $...
method mapRow (line 45) | public function mapRow(Model $model): array
FILE: app/Service/ReportExport/TimeEntriesDetailedExport.php
class TimeEntriesDetailedExport (line 27) | class TimeEntriesDetailedExport implements FromQuery, ShouldAutoSize, Wi...
method __construct (line 45) | public function __construct(Builder $builder, ExportFormat $exportForm...
method query (line 56) | public function query(): Builder
method columnFormats (line 64) | public function columnFormats(): array
method styles (line 85) | public function styles(Worksheet $sheet): array
method headings (line 96) | public function headings(): array
method map (line 117) | public function map($model): array
FILE: app/Service/ReportExport/TimeEntriesReportExport.php
class TimeEntriesReportExport (line 15) | class TimeEntriesReportExport implements FromView, ShouldAutoSize, WithC...
method __construct (line 71) | public function __construct(array $data, ExportFormat $exportFormat, s...
method view (line 81) | public function view(): View
method getCsvSettings (line 96) | public function getCsvSettings(): array
FILE: app/Service/ReportService.php
class ReportService (line 9) | class ReportService
method generateSecret (line 11) | public function generateSecret(): string
FILE: app/Service/TimeEntryAggregationService.php
class TimeEntryAggregationService (line 24) | class TimeEntryAggregationService
method getAggregatedTimeEntries (line 47) | public function getAggregatedTimeEntries(Builder $timeEntriesQuery, ?T...
method getAggregatedTimeEntriesWithDescriptions (line 226) | public function getAggregatedTimeEntriesWithDescriptions(Builder $time...
method loadDescriptorsMap (line 295) | private function loadDescriptorsMap(array $keys, TimeEntryAggregationT...
method fillGapsInTimeGroups (line 400) | public function fillGapsInTimeGroups(array $data, TimeEntryAggregation...
method getGroupByQuery (line 478) | private function getGroupByQuery(TimeEntryAggregationType $group, stri...
method timeSlotsBetween (line 517) | public function timeSlotsBetween(Carbon $start, Carbon $end, string $t...
FILE: app/Service/TimeEntryFilter.php
class TimeEntryFilter (line 13) | class TimeEntryFilter
method __construct (line 25) | public function __construct(Builder $builder)
method addEndFilter (line 30) | public function addEndFilter(?string $dateTime): self
method addEnd (line 40) | public function addEnd(?Carbon $end): self
method addStartFilter (line 50) | public function addStartFilter(?string $dateTime): self
method addStart (line 60) | public function addStart(?Carbon $start): self
method addActiveFilter (line 70) | public function addActiveFilter(?string $active): self
method addActive (line 86) | public function addActive(?bool $active): self
method addMemberIdFilter (line 97) | public function addMemberIdFilter(?Member $member): self
method addMemberIdsFilter (line 110) | public function addMemberIdsFilter(?array $memberIds): self
method addBillableFilter (line 120) | public function addBillableFilter(?string $billable): self
method addBillable (line 136) | public function addBillable(?bool $billable): self
method addClientIdsFilter (line 149) | public function addClientIdsFilter(?array $clientIds): self
method addProjectIdsFilter (line 172) | public function addProjectIdsFilter(?array $projectIds): self
method addTagIdsFilter (line 195) | public function addTagIdsFilter(?array $tagIds): self
method addTaskIdsFilter (line 220) | public function addTaskIdsFilter(?array $taskIds): self
method get (line 243) | public function get(): Builder
FILE: app/Service/TimeEntryService.php
class TimeEntryService (line 11) | class TimeEntryService
method getStartSelectRawForRounding (line 13) | public function getStartSelectRawForRounding(?TimeEntryRoundingType $r...
method getEndSelectRawForRounding (line 25) | public function getEndSelectRawForRounding(?TimeEntryRoundingType $rou...
FILE: app/Service/TimezoneService.php
class TimezoneService (line 12) | class TimezoneService
method getTimezones (line 279) | public function getTimezones(bool $inclLegacy = false): array
method getTimezoneFromUser (line 286) | public function getTimezoneFromUser(User $user): CarbonTimeZone
method getSelectOptions (line 303) | public function getSelectOptions(): array
method isValid (line 314) | public function isValid(string $timezone): bool
method mapLegacyTimezone (line 319) | public function mapLegacyTimezone(string $timezone): ?string
method getShiftFromUtc (line 324) | public function getShiftFromUtc(CarbonTimeZone $timeZone): int
FILE: app/Service/UserService.php
class UserService (line 23) | class UserService
method createUser (line 25) | public function createUser(
method assignOrganizationEntitiesToDifferentUser (line 71) | public function assignOrganizationEntitiesToDifferentUser(Organization...
method makeSureUserHasAtLeastOneOrganization (line 90) | public function makeSureUserHasAtLeastOneOrganization(User $user): void
method getOrganizationNameForUserName (line 110) | public function getOrganizationNameForUserName(string $username): string
method makeSureUserHasCurrentOrganization (line 115) | public function makeSureUserHasCurrentOrganization(User $user): void
method changeOwnership (line 132) | public function changeOwnership(Organization $organization, User $newO...
FILE: database/factories/AuditFactory.php
class AuditFactory (line 16) | class AuditFactory extends Factory
method definition (line 23) | public function definition(): array
method auditUser (line 50) | public function auditUser(User $user): self
method auditFor (line 62) | public function auditFor(Model $model): self
FILE: database/factories/ClientFactory.php
class ClientFactory (line 14) | class ClientFactory extends Factory
method definition (line 21) | public function definition(): array
method forOrganization (line 30) | public function forOrganization(Organization $organization): self
method randomCreatedAt (line 37) | public function randomCreatedAt(): self
method archived (line 46) | public function archived(): self
FILE: database/factories/MemberFactory.php
class MemberFactory (line 16) | class MemberFactory extends Factory
method definition (line 23) | public function definition(): array
method role (line 33) | public function role(Role $role): static
method forOrganization (line 42) | public function forOrganization(Organization $organization): static
method forUser (line 49) | public function forUser(User $user): static
method unverified (line 59) | public function unverified(): static
method billableRate (line 68) | public function billableRate(?int $billableRate): self
method withBillableRate (line 75) | public function withBillableRate(): self
method attachToOrganization (line 82) | public function attachToOrganization(Organization $organization, array...
FILE: database/factories/OrganizationFactory.php
class OrganizationFactory (line 20) | class OrganizationFactory extends Factory
method definition (line 27) | public function definition(): array
method billableRate (line 44) | public function billableRate(?int $billableRate): self
method withBillableRate (line 51) | public function withBillableRate(): self
method withOwner (line 58) | public function withOwner(?User $owner = null): self
method withFakeId (line 65) | public function withFakeId(): self
FILE: database/factories/OrganizationInvitationFactory.php
class OrganizationInvitationFactory (line 15) | class OrganizationInvitationFactory extends Factory
method definition (line 22) | public function definition(): array
method forOrganization (line 31) | public function forOrganization(Organization $organization): self
FILE: database/factories/Passport/ClientFactory.php
class ClientFactory (line 15) | class ClientFactory extends BaseClientFactory
method definition (line 22) | public function definition(): array
method desktopClient (line 39) | public function desktopClient(): self
method apiClient (line 47) | public function apiClient(): self
method personalAccessClient (line 55) | public function personalAccessClient(): self
method forUser (line 64) | public function forUser(User $user): self
FILE: database/factories/Passport/TokenFactory.php
class TokenFactory (line 15) | class TokenFactory extends Factory
method definition (line 22) | public function definition(): array
method forUser (line 39) | public function forUser(User $user): self
method forClient (line 48) | public function forClient(Client $client): self
FILE: database/factories/ProjectFactory.php
class ProjectFactory (line 19) | class ProjectFactory extends Factory
method definition (line 26) | public function definition(): array
method withEstimatedTime (line 41) | public function withEstimatedTime(): self
method billable (line 50) | public function billable(?int $billableRate = null): self
method createdAt (line 60) | public function createdAt(Carbon $createdAt): self
method archived (line 69) | public function archived(): self
method forOrganization (line 78) | public function forOrganization(Organization $organization): self
method isPublic (line 87) | public function isPublic(): self
method isPrivate (line 96) | public function isPrivate(): self
method addMember (line 105) | public function addMember(Member $member, array $attributes = []): self
method withClient (line 115) | public function withClient(): self
method forClient (line 124) | public function forClient(?Client $client): self
FILE: database/factories/ProjectMemberFactory.php
class ProjectMemberFactory (line 16) | class ProjectMemberFactory extends Factory
method definition (line 23) | public function definition(): array
method forUser (line 36) | public function forUser(User $user): self
method forMember (line 45) | public function forMember(Member $member): self
method forProject (line 55) | public function forProject(Project $project): self
FILE: database/factories/ReportFactory.php
class ReportFactory (line 20) | class ReportFactory extends Factory
method definition (line 27) | public function definition(): array
method randomCreatedAt (line 47) | public function randomCreatedAt(): self
method public (line 54) | public function public(): self
method private (line 62) | public function private(): self
method forOrganization (line 70) | public function forOrganization(Organization $organization): self
FILE: database/factories/TagFactory.php
class TagFactory (line 14) | class TagFactory extends Factory
method definition (line 21) | public function definition(): array
method forOrganization (line 29) | public function forOrganization(Organization $organization): self
method randomCreatedAt (line 38) | public function randomCreatedAt(): self
FILE: database/factories/TaskFactory.php
class TaskFactory (line 15) | class TaskFactory extends Factory
method definition (line 22) | public function definition(): array
method forProject (line 33) | public function forProject(Project $project): self
method isDone (line 40) | public function isDone(): self
method forOrganization (line 47) | public function forOrganization(Organization $organization): self
FILE: database/factories/TimeEntryFactory.php
class TimeEntryFactory (line 20) | class TimeEntryFactory extends Factory
method definition (line 27) | public function definition(): array
method notBillable (line 47) | public function notBillable(): self
method billableRate (line 56) | public function billableRate(int $billableRate): self
method withTask (line 66) | public function withTask(Organization $organization): self
method withTags (line 79) | public function withTags(Organization $organization): self
method startBetween (line 91) | public function startBetween(Carbon $rangeStart, Carbon $rangeEnd, boo...
method active (line 105) | public function active(): self
method forUser (line 117) | public function forUser(User $user): self
method forMember (line 126) | public function forMember(Member $member): static
method billable (line 137) | public function billable(): self
method startWithDuration (line 146) | public function startWithDuration(Carbon $start, int $durationInSecond...
method endWithDuration (line 156) | public function endWithDuration(Carbon $end, int $durationInSeconds): ...
method start (line 166) | public function start(Carbon $start): self
method forOrganization (line 175) | public function forOrganization(Organization $organization): self
method forProject (line 184) | public function forProject(?Project $project): self
method forTask (line 192) | public function forTask(?Task $task): self
FILE: database/factories/UserFactory.php
class UserFactory (line 18) | class UserFactory extends Factory
method definition (line 25) | public function definition(): array
method forCurrentOrganization (line 44) | public function forCurrentOrganization(Organization $organization): st...
method randomTimeZone (line 53) | public function randomTimeZone(): static
method placeholder (line 62) | public function placeholder(bool $placeholder = true): static
method unverified (line 74) | public function unverified(): static
method attachToOrganization (line 83) | public function attachToOrganization(Organization $organization, array...
method withProfilePicture (line 90) | public function withProfilePicture(): static
method withPersonalOrganization (line 107) | public function withPersonalOrganization(?callable $callback = null): ...
FILE: database/migrations/2014_10_12_000000_create_users_table.php
method up (line 14) | public function up(): void
method down (line 46) | public function down(): void
FILE: database/migrations/2014_10_12_100000_create_password_reset_tokens_table.php
method up (line 14) | public function up(): void
method down (line 26) | public function down(): void
FILE: database/migrations/2014_10_12_200000_add_two_factor_columns_to_users_table.php
method up (line 15) | public function up(): void
method down (line 37) | public function down(): void
FILE: database/migrations/2016_06_01_000001_create_oauth_auth_codes_table.php
method up (line 14) | public function up(): void
method down (line 29) | public function down(): void
FILE: database/migrations/2016_06_01_000002_create_oauth_access_tokens_table.php
method up (line 14) | public function up(): void
method down (line 31) | public function down(): void
FILE: database/migrations/2016_06_01_000003_create_oauth_refresh_tokens_table.php
method up (line 14) | public function up(): void
method down (line 27) | public function down(): void
FILE: database/migrations/2016_06_01_000004_create_oauth_clients_table.php
method up (line 14) | public function up(): void
method down (line 33) | public function down(): void
FILE: database/migrations/2016_06_01_000005_create_oauth_personal_access_clients_table.php
method up (line 14) | public function up(): void
method down (line 26) | public function down(): void
FILE: database/migrations/2018_08_08_100000_create_telescope_entries_table.php
method getConnection (line 14) | public function getConnection(): ?string
method up (line 22) | public function up(): void
method down (line 67) | public function down(): void
FILE: database/migrations/2019_08_19_000000_create_failed_jobs_table.php
method up (line 14) | public function up(): void
method down (line 30) | public function down(): void
FILE: database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php
method up (line 14) | public function up(): void
method down (line 31) | public function down(): void
FILE: database/migrations/2020_05_21_100000_create_organizations_table.php
method up (line 14) | public function up(): void
method down (line 30) | public function down(): void
FILE: database/migrations/2020_05_21_200000_create_organization_user_table.php
method up (line 14) | public function up(): void
method down (line 31) | public function down(): void
FILE: database/migrations/2020_05_21_300000_create_organization_invitations_table.php
method up (line 14) | public function up(): void
method down (line 32) | public function down(): void
FILE: database/migrations/2024_01_16_161030_create_sessions_table.php
method up (line 14) | public function up(): void
method down (line 29) | public function down(): void
FILE: database/migrations/2024_01_20_110218_create_clients_table.php
method up (line 14) | public function up(): void
method down (line 32) | public function down(): void
FILE: database/migrations/2024_01_20_110439_create_projects_table.php
method up (line 14) | public function up(): void
method down (line 41) | public function down(): void
FILE: database/migrations/2024_01_20_110444_create_tasks_table.php
method up (line 14) | public function up(): void
method down (line 38) | public function down(): void
FILE: database/migrations/2024_01_20_110452_create_tags_table.php
method up (line 14) | public function up(): void
method down (line 34) | public function down(): void
FILE: database/migrations/2024_01_20_110837_create_time_entries_table.php
method up (line 14) | public function up(): void
method down (line 59) | public function down(): void
FILE: database/migrations/2024_03_26_171253_create_project_members_table.php
method up (line 14) | public function up(): void
method down (line 39) | public function down(): void
FILE: database/migrations/2024_04_11_150130_create_jobs_table.php
method up (line 14) | public function up(): void
method down (line 30) | public function down(): void
FILE: database/migrations/2024_04_12_095010_create_cache_table.php
method up (line 14) | public function up(): void
method down (line 32) | public function down(): void
FILE: database/migrations/2024_05_07_134711_move_from_user_id_to_member_id_in_project_members_table.php
method up (line 15) | public function up(): void
method down (line 39) | public function down(): void
FILE: database/migrations/2024_05_07_141842_move_from_user_id_to_member_id_in_time_entries_table.php
method up (line 15) | public function up(): void
method down (line 40) | public function down(): void
FILE: database/migrations/2024_05_13_171020_rename_table_organization_user_to_members.php
method up (line 13) | public function up(): void
method down (line 21) | public function down(): void
FILE: database/migrations/2024_05_22_151226_add_client_id_to_time_entries_table.php
method up (line 15) | public function up(): void
method down (line 36) | public function down(): void
FILE: database/migrations/2024_05_30_175801_add_is_billable_column_to_projects_table.php
method up (line 15) | public function up(): void
method down (line 33) | public function down(): void
FILE: database/migrations/2024_05_30_175825_add_is_imported_column_to_time_entries_table.php
method up (line 14) | public function up(): void
method down (line 24) | public function down(): void
FILE: database/migrations/2024_06_01_000001_create_oauth_device_codes_table.php
method up (line 14) | public function up(): void
method down (line 32) | public function down(): void
method getConnection (line 40) | public function getConnection(): ?string
FILE: database/migrations/2024_06_07_113443_change_member_id_foreign_keys_to_restrict_on_delete.php
method up (line 14) | public function up(): void
method down (line 51) | public function down(): void
FILE: database/migrations/2024_06_10_161831_reset_billable_rates_with_zero_as_value.php
method up (line 12) | public function up(): void
method down (line 34) | public function down(): void
FILE: database/migrations/2024_06_21_122754_add_is_archived_columns_to_projects_and_clients_table.php
method up (line 14) | public function up(): void
method down (line 27) | public function down(): void
FILE: database/migrations/2024_06_24_114433_add_done_at_to_tasks_table.php
method up (line 14) | public function up(): void
method down (line 24) | public function down(): void
FILE: database/migrations/2024_07_02_134307_add_estimated_time_to_projects_and_tasks_table.php
method up (line 14) | public function up(): void
method down (line 27) | public function down(): void
FILE: database/migrations/2024_07_03_145445_change_data_type_of_id_column_in_failed_jobs_table.php
method up (line 14) | public function up(): void
method down (line 28) | public function down(): void
FILE: database/migrations/2024_07_18_080906_add_still_active_email_sent_at_to_time_entries_table.php
method up (line 14) | public function up(): void
method down (line 24) | public function down(): void
FILE: database/migrations/2024_08_01_104840_create_reports_table.php
method up (line 14) | public function up(): void
method down (line 37) | public function down(): void
FILE: database/migrations/2024_09_02_094105_create_audits_table.php
class CreateAuditsTable (line 9) | class CreateAuditsTable extends Migration
method up (line 14) | public function up(): void
method down (line 43) | public function down(): void
FILE: database/migrations/2024_09_18_120203_add_spent_time_to_projects_and_tasks_table.php
method up (line 14) | public function up(): void
method down (line 27) | public function down(): void
FILE: database/migrations/2024_10_01_143608_add_employees_can_see_billable_rates_to_organizations_table.php
method up (line 14) | public function up(): void
method down (line 24) | public function down(): void
FILE: database/migrations/2024_11_04_164807_add_foreign_key_to_organizations_and_members_table.php
method up (line 15) | public function up(): void
method down (line 83) | public function down(): void
FILE: database/migrations/2024_11_04_170614_add_foreign_keys_to_oauth_tables.php
method up (line 15) | public function up(): void
method down (line 97) | public function down(): void
FILE: database/migrations/2025_04_03_101827_add_localization_columns_to_organizations_table.php
method up (line 14) | public function up(): void
method down (line 36) | public function down(): void
FILE: database/migrations/2025_04_25_202047_change_data_type_for_spent_time_columns.php
method up (line 14) | public function up(): void
method down (line 27) | public function down(): void
FILE: database/migrations/2025_05_06_152804_fix_typos_in_organizations_table_format_columns.php
method up (line 12) | public function up(): void
method down (line 30) | public function down(): void
FILE: database/migrations/2025_05_16_075757_add_foreign_key_for_current_team_id_in_users_table.php
method up (line 14) | public function up(): void
method down (line 37) | public function down(): void
FILE: database/migrations/2025_06_30_095942_remove_oauth_personal_access_clients_table.php
method up (line 14) | public function up(): void
method down (line 22) | public function down(): void
FILE: database/migrations/2025_06_30_132538_update_oauth_clients_table.php
method up (line 14) | public function up(): void
method down (line 78) | public function down(): void
FILE: database/migrations/2025_07_15_105949_hash_oauth_clients.php
method up (line 12) | public function up(): void
method down (line 31) | public function down(): void
FILE: database/migrations/2025_07_17_104903_add_reminder_sent_at_to_oauth_access_tokens_table.php
method up (line 14) | public function up(): void
method down (line 25) | public function down(): void
FILE: database/migrations/2025_10_02_000001_add_prevent_overlapping_time_entries_to_organizations_table.php
method up (line 14) | public function up(): void
method down (line 24) | public function down(): void
FILE: database/migrations/2025_10_16_000001_extend_time_entry_description.php
method up (line 14) | public function up(): void
method down (line 24) | public function down(): void
FILE: database/migrations/2025_10_24_120845_add_employees_can_manage_tasks_to_organizations_table.php
method up (line 14) | public function up(): void
method down (line 24) | public function down(): void
FILE: database/schema/pgsql_test-schema.sql
type public (line 27) | CREATE TABLE public.cache (
type public (line 38) | CREATE TABLE public.cache_locks (
type public (line 49) | CREATE TABLE public.clients (
type public (line 62) | CREATE TABLE public.customers (
type public (line 80) | CREATE TABLE public.failed_jobs (
type public (line 95) | CREATE TABLE public.jobs (
type public (line 129) | CREATE TABLE public.members (
type public (line 144) | CREATE TABLE public.migrations (
type public (line 175) | CREATE TABLE public.oauth_access_tokens (
type public (line 192) | CREATE TABLE public.oauth_auth_codes (
type public (line 206) | CREATE TABLE public.oauth_clients (
type public (line 225) | CREATE TABLE public.oauth_personal_access_clients (
type public (line 256) | CREATE TABLE public.oauth_refresh_tokens (
type public (line 268) | CREATE TABLE public.organization_invitations (
type public (line 282) | CREATE TABLE public.organizations (
type public (line 298) | CREATE TABLE public.password_reset_tokens (
type public (line 309) | CREATE TABLE public.personal_access_tokens (
type public (line 327) | CREATE TABLE public.project_members (
type public (line 342) | CREATE TABLE public.projects (
type public (line 360) | CREATE TABLE public.sessions (
type public (line 374) | CREATE TABLE public.subscription_items (
type public (line 390) | CREATE TABLE public.subscriptions (
type public (line 409) | CREATE TABLE public.tags (
type public (line 422) | CREATE TABLE public.tasks (
type public (line 436) | CREATE TABLE public.time_entries (
type public (line 460) | CREATE TABLE public.transactions (
type public (line 481) | CREATE TABLE public.users (
type customers_billable_id_billable_type_index (line 815) | CREATE INDEX customers_billable_id_billable_type_index ON public.custome...
type jobs_queue_index (line 822) | CREATE INDEX jobs_queue_index ON public.jobs USING btree (queue)
type oauth_access_tokens_user_id_index (line 829) | CREATE INDEX oauth_access_tokens_user_id_index ON public.oauth_access_to...
type oauth_auth_codes_user_id_index (line 836) | CREATE INDEX oauth_auth_codes_user_id_index ON public.oauth_auth_codes U...
type oauth_clients_user_id_index (line 843) | CREATE INDEX oauth_clients_user_id_index ON public.oauth_clients USING b...
type oauth_refresh_tokens_access_token_id_index (line 850) | CREATE INDEX oauth_refresh_tokens_access_token_id_index ON public.oauth_...
type organizations_user_id_index (line 857) | CREATE INDEX organizations_user_id_index ON public.organizations USING b...
type personal_access_tokens_tokenable_type_tokenable_id_index (line 864) | CREATE INDEX personal_access_tokens_tokenable_type_tokenable_id_index ON...
type sessions_last_activity_index (line 871) | CREATE INDEX sessions_last_activity_index ON public.sessions USING btree...
type sessions_user_id_index (line 878) | CREATE INDEX sessions_user_id_index ON public.sessions USING btree (user...
type subscriptions_billable_id_billable_type_index (line 885) | CREATE INDEX subscriptions_billable_id_billable_type_index ON public.sub...
type tags_created_at_index (line 892) | CREATE INDEX tags_created_at_index ON public.tags USING btree (created_at)
type time_entries_billable_index (line 899) | CREATE INDEX time_entries_billable_index ON public.time_entries USING bt...
type time_entries_end_index (line 906) | CREATE INDEX time_entries_end_index ON public.time_entries USING btree (...
type time_entries_start_index (line 913) | CREATE INDEX time_entries_start_index ON public.time_entries USING btree...
type transactions_billable_id_billable_type_index (line 920) | CREATE INDEX transactions_billable_id_billable_type_index ON public.tran...
type transactions_paddle_subscription_id_index (line 927) | CREATE INDEX transactions_paddle_subscription_id_index ON public.transac...
type users_email_unique (line 934) | CREATE UNIQUE INDEX users_email_unique ON public.users USING btree (emai...
FILE: database/seeders/DatabaseSeeder.php
class DatabaseSeeder (line 30) | class DatabaseSeeder extends Seeder
method run (line 35) | public function run(): void
method deleteAll (line 202) | private function deleteAll(): void
FILE: e2e/auth.spec.ts
function registerNewUser (line 5) | async function registerNewUser(page, email, password) {
FILE: e2e/calendar-settings.spec.ts
function goToCalendar (line 6) | async function goToCalendar(page: Page) {
function openSettingsPopover (line 11) | async function openSettingsPopover(page: Page) {
function clearCalendarSettings (line 16) | async function clearCalendarSettings(page: Page) {
FILE: e2e/calendar.spec.ts
function goToCalendar (line 12) | async function goToCalendar(page: Page) {
FILE: e2e/clients.spec.ts
function goToClientsOverview (line 13) | async function goToClientsOverview(page: Page) {
function clearClientTableState (line 139) | async function clearClientTableState(page: Page) {
FILE: e2e/command-palette.spec.ts
constant TIMER_BUTTON_SELECTOR (line 5) | const TIMER_BUTTON_SELECTOR = '[data-testid="dashboard_timer"] [data-tes...
function goToDashboard (line 7) | async function goToDashboard(page: Page) {
function openCommandPalette (line 11) | async function openCommandPalette(page: Page) {
function closeCommandPalette (line 16) | async function closeCommandPalette(page: Page) {
function searchInCommandPalette (line 21) | async function searchInCommandPalette(page: Page, query: string) {
function selectCommand (line 27) | async function selectCommand(page: Page, name: string) {
function assertTimerIsRunning (line 33) | async function assertTimerIsRunning(page: Page) {
function assertTimerIsStopped (line 42) | async function assertTimerIsStopped(page: Page) {
FILE: e2e/dashboard.spec.ts
function goToDashboard (line 18) | async function goToDashboard(page: Page) {
FILE: e2e/import-export.spec.ts
function goToImportExport (line 6) | async function goToImportExport(page: Page) {
FILE: e2e/members.spec.ts
function goToMembersPage (line 19) | async function goToMembersPage(page: Page) {
function openInviteMemberModal (line 23) | async function openInviteMemberModal(page: Page) {
function clearMemberTableState (line 631) | async function clearMemberTableState(page: Page) {
FILE: e2e/organization.spec.ts
function goToOrganizationSettings (line 4) | async function goToOrganizationSettings(page) {
function createTimeEntry (line 10) | async function createTimeEntry(page, duration: string) {
FILE: e2e/profile.spec.ts
function goToProfilePage (line 5) | async function goToProfilePage(page: Page) {
function createNewApiToken (line 30) | async function createNewApiToken(page) {
FILE: e2e/project-members.spec.ts
function createProjectWithMemberViaApi (line 8) | async function createProjectWithMemberViaApi(ctx: TestContext, page: Pag...
FILE: e2e/projects.spec.ts
function goToProjectsOverview (line 16) | async function goToProjectsOverview(page: Page) {
function clearProjectTableState (line 21) | async function clearProjectTableState(page: Page) {
function selectStatusFilter (line 65) | async function selectStatusFilter(page: Page, status: 'Active' | 'Archiv...
function removeStatusFilter (line 75) | async function removeStatusFilter(page: Page) {
FILE: e2e/shared-reports.spec.ts
constant DATE_PICKER_BUTTON_PATTERN (line 26) | const DATE_PICKER_BUTTON_PATTERN =
FILE: e2e/tags.spec.ts
function goToTagsOverview (line 8) | async function goToTagsOverview(page: Page) {
function clearTagTableState (line 97) | async function clearTagTableState(page: Page) {
FILE: e2e/tasks.spec.ts
function goToProjectsOverview (line 13) | async function goToProjectsOverview(page: Page) {
FILE: e2e/time.spec.ts
constant DATE_PICKER_BUTTON_PATTERN (line 22) | const DATE_PICKER_BUTTON_PATTERN =
constant DATE_DISPLAY_PATTERN (line 25) | const DATE_DISPLAY_PATTERN = /^\d{4}-\d{2}-\d{2}$|^\d{2}\/\d{2}\/\d{4}$|...
function getDayFromTimestamp (line 30) | function getDayFromTimestamp(timestamp: string): number {
function getMonthFromTimestamp (line 37) | function getMonthFromTimestamp(timestamp: string): number {
function goToTimeOverview (line 41) | async function goToTimeOverview(page: Page) {
function goToOrganizationSettings (line 45) | async function goToOrganizationSettings(page: Page) {
function createEmptyTimeEntry (line 51) | async function createEmptyTimeEntry(page: Page) {
function assertThatTimeEntryRowIsStopped (line 88) | async function assertThatTimeEntryRowIsStopped(newTimeEntry: Locator) {
FILE: e2e/timetracker.spec.ts
constant DATE_DISPLAY_PATTERN (line 15) | const DATE_DISPLAY_PATTERN = /^\d{4}-\d{2}-\d{2}$|^\d{2}\/\d{2}\/\d{4}$|...
function goToDashboard (line 17) | async function goToDashboard(page: Page) {
FILE: e2e/utils/api.ts
type TestContext (line 9) | interface TestContext {
function createApiToken (line 30) | async function createApiToken(page: Page): Promise<string> {
function bearerHeaders (line 68) | function bearerHeaders(token: string): Record<string, string> {
function setupTestContext (line 79) | async function setupTestContext(page: Page): Promise<TestContext> {
function createAuthenticatedRequest (line 89) | function createAuthenticatedRequest(
function getOrganizationId (line 118) | async function getOrganizationId(
function getCurrentMemberId (line 130) | async function getCurrentMemberId(
function parseDurationToSeconds (line 148) | function parseDurationToSeconds(duration: string): number {
function createTimestamps (line 173) | function createTimestamps(duration: string): { start: string; end: strin...
function formatTimestamp (line 185) | function formatTimestamp(date: Date): string {
function randomColor (line 189) | function randomColor(): string {
function createPublicProjectViaApi (line 207) | async function createPublicProjectViaApi(
function createProjectViaApi (line 222) | async function createProjectViaApi(
function archiveProjectViaApi (line 253) | async function archiveProjectViaApi(
function createBillableProjectViaApi (line 284) | async function createBillableProjectViaApi(
function createClientViaApi (line 295) | async function createClientViaApi(ctx: TestContext, data: { name: string...
function createProjectWithClientViaApi (line 305) | async function createProjectWithClientViaApi(
function createTaskViaApi (line 318) | async function createTaskViaApi(
function createTagViaApi (line 336) | async function createTagViaApi(ctx: TestContext, data: { name: string }) {
function createTimeEntryViaApi (line 346) | async function createTimeEntryViaApi(
function createProjectMemberViaApi (line 378) | async function createProjectMemberViaApi(
function getMembersViaApi (line 397) | async function getMembersViaApi(ctx: TestContext) {
function updateMemberBillableRateViaApi (line 413) | async function updateMemberBillableRateViaApi(
function createTimeEntryWithProjectViaApi (line 431) | async function createTimeEntryWithProjectViaApi(
function createTimeEntryWithProjectAndTaskViaApi (line 445) | async function createTimeEntryWithProjectAndTaskViaApi(
function createTimeEntryWithTagViaApi (line 462) | async function createTimeEntryWithTagViaApi(
function createBareTimeEntryViaApi (line 476) | async function createBareTimeEntryViaApi(
function createTimeEntryWithBillableStatusViaApi (line 484) | async function createTimeEntryWithBillableStatusViaApi(
function createPlaceholderMemberViaImportApi (line 500) | async function createPlaceholderMemberViaImportApi(
function updateOrganizationSettingViaApi (line 529) | async function updateOrganizationSettingViaApi(
function updateOrganizationCurrencyViaWeb (line 542) | async function updateOrganizationCurrencyViaWeb(
function createMultipleTimeEntriesViaApi (line 563) | async function createMultipleTimeEntriesViaApi(
function getInvitationsViaApi (line 583) | async function getInvitationsViaApi(ctx: TestContext) {
FILE: e2e/utils/currentTimeEntry.ts
function startOrStopTimerWithButton (line 4) | async function startOrStopTimerWithButton(page: Page) {
function assertThatTimerHasStarted (line 12) | async function assertThatTimerHasStarted(page: Page) {
function newTimeEntryResponse (line 21) | function newTimeEntryResponse(
function assertThatTimerIsStopped (line 42) | async function assertThatTimerIsStopped(page: Page) {
function stoppedTimeEntryResponse (line 51) | async function stoppedTimeEntryResponse(page: Page, { description = '', ...
FILE: e2e/utils/mailpit.ts
function searchEmails (line 8) | async function searchEmails(
function getMessage (line 19) | async function getMessage(
function getInvitationAcceptUrl (line 31) | async function getInvitationAcceptUrl(
function getPasswordResetUrl (line 59) | async function getPasswordResetUrl(
FILE: e2e/utils/members.ts
function registerUser (line 10) | async function registerUser(
function inviteAndAcceptMember (line 41) | async function inviteAndAcceptMember(
function setupAdminUser (line 75) | async function setupAdminUser(
function setupEmployeeUser (line 162) | async function setupEmployeeUser(
FILE: e2e/utils/money.ts
function formatCentsWithOrganizationDefaults (line 5) | function formatCentsWithOrganizationDefaults(
FILE: e2e/utils/reporting.ts
function goToReporting (line 9) | async function goToReporting(page: Page) {
function goToReportingDetailed (line 13) | async function goToReportingDetailed(page: Page) {
function createProject (line 21) | async function createProject(page: Page, projectName: string) {
function createBillableProject (line 38) | async function createBillableProject(page: Page, projectName: string) {
function createClient (line 57) | async function createClient(page: Page, clientName: string) {
function createProjectWithClient (line 74) | async function createProjectWithClient(page: Page, projectName: string, ...
function createTask (line 96) | async function createTask(page: Page, projectName: string, taskName: str...
function createTimeEntryWithProject (line 118) | async function createTimeEntryWithProject(
function createTimeEntryWithProjectAndTask (line 147) | async function createTimeEntryWithProjectAndTask(
function createTimeEntryWithTag (line 184) | async function createTimeEntryWithTag(page: Page, tagName: string, durat...
function createBareTimeEntry (line 217) | async function createBareTimeEntry(page: Page, description: string, dura...
function createTimeEntryWithBillableStatus (line 236) | async function createTimeEntryWithBillableStatus(
function waitForReportingUpdate (line 275) | async function waitForReportingUpdate(page: Page) {
function waitForDetailedReportingUpdate (line 282) | async function waitForDetailedReportingUpdate(page: Page) {
function goToReportingShared (line 296) | async function goToReportingShared(page: Page) {
function saveAsSharedReport (line 300) | async function saveAsSharedReport(
FILE: e2e/utils/table.ts
function getTableRowNames (line 7) | async function getTableRowNames(table: Locator): Promise<string[]> {
FILE: e2e/utils/tags.ts
function newTagResponse (line 3) | function newTagResponse(page: Page, { name = '' } = {}) {
FILE: playwright/config.ts
constant PLAYWRIGHT_BASE_URL (line 1) | const PLAYWRIGHT_BASE_URL = process.env.PLAYWRIGHT_BASE_URL ?? 'http://s...
constant MAILPIT_BASE_URL (line 2) | const MAILPIT_BASE_URL = process.env.MAILPIT_BASE_URL ?? 'http://mailpit...
constant TEST_USER_PASSWORD (line 3) | const TEST_USER_PASSWORD = 'amazingpassword123';
FILE: playwright/fixtures.ts
type EmployeeFixture (line 10) | interface EmployeeFixture {
type AdminFixture (line 15) | interface AdminFixture {
FILE: resources/js/Components/Common/Project/constants.ts
constant NO_CLIENT_ID (line 1) | const NO_CLIENT_ID = '__no_client__';
FILE: resources/js/app.ts
method setup (line 43) | setup({ el, App, props, plugin }) {
FILE: resources/js/lib/utils.ts
function cn (line 4) | function cn(...inputs: ClassValue[]) {
FILE: resources/js/packages/api/src/index.ts
type SolidTimeApi (line 9) | type SolidTimeApi = ApiOf<typeof api>;
type InvitationsIndexResponse (line 11) | type InvitationsIndexResponse = ZodiosResponseByAlias<SolidTimeApi, 'get...
type CreateInvitationBody (line 13) | type CreateInvitationBody = ZodiosBodyByAlias<SolidTimeApi, 'invite'>;
type Invitation (line 15) | type Invitation = InvitationsIndexResponse['data'][0];
type TimeEntryResponse (line 17) | type TimeEntryResponse = ZodiosResponseByAlias<SolidTimeApi, 'getTimeEnt...
type TimeEntry (line 18) | type TimeEntry = TimeEntryResponse['data'][0];
type CreateTimeEntryBody (line 20) | type CreateTimeEntryBody = ZodiosBodyByAlias<SolidTimeApi, 'createTimeEn...
type UpdateMultipleTimeEntriesBody (line 22) | type UpdateMultipleTimeEntriesBody = ZodiosBodyByAlias<
type UpdateMultipleTimeEntriesChangeset (line 27) | type UpdateMultipleTimeEntriesChangeset = UpdateMultipleTimeEntriesBody[...
type ProjectResponse (line 29) | type ProjectResponse = ZodiosResponseByAlias<SolidTimeApi, 'getProjects'>;
type Project (line 30) | type Project = ProjectResponse['data'][0];
type CreateProjectBody (line 32) | type CreateProjectBody = ZodiosBodyByAlias<SolidTimeApi, 'createProject'>;
type UpdateProjectBody (line 34) | type UpdateProjectBody = ZodiosBodyByAlias<SolidTimeApi, 'updateProject'>;
type ProjectMemberResponse (line 36) | type ProjectMemberResponse = ZodiosResponseByAlias<SolidTimeApi, 'getPro...
type CreateProjectMemberBody (line 38) | type CreateProjectMemberBody = ZodiosBodyByAlias<SolidTimeApi, 'createPr...
type UpdateProjectMemberBody (line 40) | type UpdateProjectMemberBody = ZodiosBodyByAlias<SolidTimeApi, 'updatePr...
type ProjectMember (line 42) | type ProjectMember = ProjectMemberResponse['data'][0];
type CreateTaskBody (line 44) | type CreateTaskBody = ZodiosBodyByAlias<SolidTimeApi, 'createTask'>;
type CreateClientBody (line 46) | type CreateClientBody = ZodiosBodyByAlias<SolidTimeApi, 'createClient'>;
type UpdateClientBody (line 47) | type UpdateClientBody = ZodiosBodyByAlias<SolidTimeApi, 'updateClient'>;
type TagIndexResponse (line 49) | type TagIndexResponse = ZodiosResponseByAlias<SolidTimeApi, 'getTags'>;
type Tag (line 50) | type Tag = TagIndexResponse['data'][0];
type TaskIndexResponse (line 52) | type TaskIndexResponse = ZodiosResponseByAlias<SolidTimeApi, 'getTasks'>;
type Task (line 53) | type Task = TaskIndexResponse['data'][0];
type UpdateTaskBody (line 55) | type UpdateTaskBody = ZodiosBodyByAlias<SolidTimeApi, 'updateTask'>;
type ClientIndexResponse (line 57) | type ClientIndexResponse = ZodiosResponseByAlias<SolidTimeApi, 'getClien...
type Client (line 58) | type Client = ClientIndexResponse['data'][0];
type MemberIndexResponse (line 60) | type MemberIndexResponse = ZodiosResponseByAlias<SolidTimeApi, 'getMembe...
type Member (line 61) | type Member = MemberIndexResponse['data'][0];
type UpdateMemberBody (line 63) | type UpdateMemberBody = ZodiosBodyByAlias<SolidTimeApi, 'updateMember'>;
type InviteMemberBody (line 65) | type InviteMemberBody = ZodiosBodyByAlias<SolidTimeApi, 'invite'>;
type MemberRole (line 66) | type MemberRole = InviteMemberBody['role'];
type CreateTagBody (line 68) | type CreateTagBody = ZodiosBodyByAlias<SolidTimeApi, 'createTag'>;
type UpdateTagBody (line 69) | type UpdateTagBody = ZodiosBodyByAlias<SolidTimeApi, 'updateTag'>;
type ImportType (line 71) | type ImportType = ZodiosResponseByAlias<SolidTimeApi, 'getImporters'>['d...
type ImportReport (line 72) | type ImportReport = ZodiosResponseByAlias<SolidTimeApi, 'importData'>;
type ReportingResponse (line 74) | type ReportingResponse = ZodiosResponseByAlias<SolidTimeApi, 'getAggrega...
type AggregatedTimeEntries (line 76) | type AggregatedTimeEntries = ReportingResponse['data'];
type GroupedDataEntries (line 77) | type GroupedDataEntries = ReportingResponse['data']['grouped_data'];
type TimeEntriesQueryParams (line 79) | type TimeEntriesQueryParams = ZodiosQueryParamsByAlias<SolidTimeApi, 'ge...
type AggregatedTimeEntriesQueryParams (line 81) | type AggregatedTimeEntriesQueryParams = ZodiosQueryParamsByAlias<
type OrganizationResponse (line 91) | type OrganizationResponse = ZodiosResponseByAlias<SolidTimeApi, 'getOrga...
type Organization (line 93) | type Organization = ZodiosResponseByAlias<SolidTimeApi, 'getOrganization...
type UpdateOrganizationBody (line 95) | type UpdateOrganizationBody = ZodiosBodyByAlias<SolidTimeApi, 'updateOrg...
type MyMemberships (line 97) | type MyMemberships = ZodiosResponseByAlias<SolidTimeApi, 'getMyMembershi...
type MyMembership (line 99) | type MyMembership = MyMemberships[0];
type OrganizationExportResponse (line 101) | type OrganizationExportResponse = ZodiosResponseByAlias<SolidTimeApi, 'e...
type ReportIndexResponse (line 103) | type ReportIndexResponse = ZodiosResponseByAlias<SolidTimeApi, 'getRepor...
type CreateReportBody (line 105) | type CreateReportBody = ZodiosBodyByAlias<SolidTimeApi, 'createReport'>;
type UpdateReportBody (line 106) | type UpdateReportBody = ZodiosBodyByAlias<SolidTimeApi, 'updateReport'>;
type CreateReportBodyProperties (line 107) | type CreateReportBodyProperties = CreateReportBody['properties'];
type Report (line 108) | type Report = ReportIndexResponse['data'][0];
type ApiTokenIndexResponse (line 110) | type ApiTokenIndexResponse = ZodiosResponseByAlias<SolidTimeApi, 'getApi...
type CreateApiTokenBody (line 112) | type CreateApiTokenBody = ZodiosBodyByAlias<SolidTimeApi, 'createApiToke...
type ApiToken (line 113) | type ApiToken = ApiTokenIndexResponse['data'][0];
type DetailedInvoiceResponse (line 115) | type DetailedInvoiceResponse = ZodiosResponseByAlias<SolidTimeApi, 'getI...
type InvoiceIndexEntry (line 117) | type InvoiceIndexEntry = ZodiosResponseByAlias<SolidTimeApi, 'getInvoice...
type UpdateInvoiceSettings (line 119) | type UpdateInvoiceSettings = ZodiosBodyByAlias<SolidTimeApi, 'updateInvo...
type CreateInvoiceBody (line 121) | type CreateInvoiceBody = ZodiosBodyByAlias<SolidTimeApi, 'createInvoice'>;
type UpdateInvoiceBody (line 123) | type UpdateInvoiceBody = ZodiosBodyByAlias<SolidTimeApi, 'updateInvoice'>;
FILE: resources/js/packages/api/src/openapi.json.client.ts
function createApiClient (line 4625) | function createApiClient(baseUrl: string, options?: ZodiosOptions) {
FILE: resources/js/packages/ui/src/Buttons/index.ts
type ButtonVariants (line 35) | type ButtonVariants = VariantProps<typeof buttonVariants>;
FILE: resources/js/packages/ui/src/CommandPalette/CommandPaletteTypes.ts
type CommandPaletteCommand (line 4) | interface CommandPaletteCommand {
type CommandPaletteGroup (line 13) | interface CommandPaletteGroup {
type EntitySearchResult (line 19) | interface EntitySearchResult extends CommandPaletteCommand {
FILE: resources/js/packages/ui/src/FullCalendar/calendarSettings.ts
type CalendarSettings (line 1) | interface CalendarSettings {
FILE: resources/js/packages/ui/src/FullCalendar/idleStatusPlugin.ts
type WindowActivityInPeriod (line 4) | interface WindowActivityInPeriod {
type ActivityPeriod (line 11) | interface ActivityPeriod {
type ActivityStatusPluginOptions (line 18) | interface ActivityStatusPluginOptions {
function getOrCreateTooltip (line 29) | function getOrCreateTooltip(): HTMLElement {
function showTooltip (line 48) | function showTooltip(box: HTMLElement, tooltip: HTMLElement, content: st...
function hideTooltip (line 81) | function hideTooltip(tooltip: HTMLElement) {
function formatDuration (line 95) | function formatDuration(durationMinutes: number): string {
function createTooltipContent (line 104) | function createTooltipContent(
function renderActivityStatusBoxes (line 198) | function renderActivityStatusBoxes(
function getSlotDuration (line 311) | function getSlotDuration(calendarEl: HTMLElement): number {
function calculateBoxPosition (line 336) | function calculateBoxPosition(
function cleanupActivityStatusPlugin (line 368) | function cleanupActivityStatusPlugin() {
FILE: resources/js/packages/ui/src/FullCalendar/useVisualSnap.ts
type VisualSnapOptions (line 4) | interface VisualSnapOptions {
function useVisualSnap (line 11) | function useVisualSnap({
FILE: resources/js/packages/ui/src/field/index.ts
type FieldVariants (line 28) | type FieldVariants = VariantProps<typeof fieldVariants>;
FILE: resources/js/packages/ui/src/index.ts
type Window (line 2) | interface Window {
FILE: resources/js/packages/ui/src/utils/cn.ts
function cn (line 4) | function cn(...inputs: ClassValue[]) {
FILE: resources/js/packages/ui/src/utils/color.ts
function getRandomColor (line 25) | function getRandomColor() {
function getRandomColorWithSeed (line 29) | function getRandomColorWithSeed(seed: string) {
FILE: resources/js/packages/ui/src/utils/money.ts
type CurrencyFormat (line 3) | type CurrencyFormat =
function formatMoney (line 11) | function formatMoney(
function formatCents (line 36) | function formatCents(
function getOrganizationCurrencySymbol (line 46) | function getOrganizationCurrencySymbol(currency: string) {
FILE: resources/js/packages/ui/src/utils/number.ts
type NumberFormat (line 1) | type NumberFormat =
function formatNumber (line 14) | function formatNumber(value: number, format?: string): string {
FILE: resources/js/packages/ui/src/utils/random.ts
class Prando (line 6) | class Prando {
method constructor (line 21) | constructor(seed?: number | string) {
method next (line 47) | public next(min = 0, pseudoMax = 1): number {
method nextInt (line 59) | public nextInt(min = 10, max = 100): number {
method nextString (line 75) | public nextString(
method nextChar (line 92) | public nextChar(
method nextArrayItem (line 109) | public nextArrayItem<T>(array: T[]): T {
method nextBoolean (line 118) | public nextBoolean(): boolean {
method skip (line 130) | public skip(iterations = 1): void {
method reset (line 149) | public reset(): void {
method recalculate (line 156) | private recalculate(): void {
method xorshift (line 160) | private xorshift(value: number): number {
method map (line 169) | private map(
method hashCode (line 179) | private hashCode(str: string): number {
method getSafeSeed (line 192) | private getSafeSeed(seed: number): number {
FILE: resources/js/packages/ui/src/utils/select.ts
function useSelectEvents (line 4) | function useSelectEvents<Type>(
FILE: resources/js/packages/ui/src/utils/settings.ts
function getWeekStart (line 1) | function getWeekStart() {
function getUserTimezone (line 11) | function getUserTimezone() {
FILE: resources/js/packages/ui/src/utils/time.ts
type DateFormat (line 16) | type DateFormat =
type WeekStartDay (line 25) | type WeekStartDay = 0 | 1 | 2 | 3 | 4 | 5 | 6;
type TimeFormat (line 36) | type TimeFormat = '12-hours' | '24-hours';
type IntervalFormat (line 37) | type IntervalFormat =
type TimeInputUnit (line 42) | type TimeInputUnit = 'minutes' | 'hours';
function getDayJsInstance (line 53) | function getDayJsInstance() {
function formatHumanReadableDuration (line 73) | function formatHumanReadableDuration(
function formatDuration (line 97) | function formatDuration(duration: number): string {
function calculateDifference (line 105) | function calculateDifference(start: string, end: string | null) {
function formatTime (line 117) | function formatTime(date: string, timeFormat: TimeFormat = '24-hours') {
function getLocalizedDayJs (line 122) | function getLocalizedDayJs(timestamp?: string | null) {
function getLocalizedDateFromTimestamp (line 126) | function getLocalizedDateFromTimestamp(timestamp: string) {
function formatDate (line 134) | function formatDate(date: string, format: DateFormat = 'point-separated-...
function formatDateLocalized (line 145) | function formatDateLocalized(
function formatDateTimeLocalized (line 152) | function formatDateTimeLocalized(
function formatWeek (line 161) | function formatWeek(date: string | null): string {
function formatHumanReadableDate (line 169) | function formatHumanReadableDate(date: string) {
function formatWeekday (line 195) | function formatWeekday(date: string) {
function formatStartEnd (line 199) | function formatStartEnd(
function parseTimeInput (line 211) | function parseTimeInput(
FILE: resources/js/types/dom.d.ts
type HtmlButtonType (line 1) | type HtmlButtonType = 'button' | 'submit' | 'reset';
FILE: resources/js/types/dom.ts
type HtmlButtonType (line 1) | type HtmlButtonType = 'button' | 'submit' | 'reset';
FILE: resources/js/types/global.d.ts
type Window (line 8) | interface Window {
type ComponentCustomProperties (line 20) | interface ComponentCustomProperties {
type PageProps (line 26) | interface PageProps extends InertiaPageProps, AppPageProps {}
FILE: resources/js/types/inertia.d.ts
type Props (line 4) | interface Props {
FILE: resources/js/types/jetstream.ts
type Permissions (line 3) | interface Permissions {
type Session (line 11) | interface Session {
type Membership (line 23) | interface Membership {
type Role (line 27) | interface Role {
type JetstreamUser (line 33) | type JetstreamUser = User & {
type Token (line 36) | interface Token {
FILE: resources/js/types/models.d.ts
type Client (line 1) | interface Client {
type Membership (line 9) | interface Membership {
type Organization (line 17) | interface Organization {
type OrganizationInvitation (line 29) | interface OrganizationInvitation {
type Project (line 39) | interface Project {
type Task (line 51) | interface Task {
type OrganizationWithMembership (line 61) | type OrganizationWithMembership = Organization & {
type User (line 64) | interface User {
FILE: resources/js/types/models.ts
type Client (line 1) | interface Client {
type Membership (line 12) | interface Membership {
type Organization (line 22) | interface Organization {
type OrganizationInvitation (line 37) | interface OrganizationInvitation {
type Project (line 50) | interface Project {
type Task (line 65) | interface Task {
type OrganizationWithMembership (line 78) | type OrganizationWithMembership = Organization & { membership: Membershi...
type User (line 80) | interface User {
FILE: resources/js/types/projects.d.ts
type BillableKey (line 1) | type BillableKey = 'non-billable' | 'default-rate' | 'custom-rate';
FILE: resources/js/types/reporting.ts
type ExportFormat (line 1) | type ExportFormat = 'xlsx' | 'csv' | 'ods' | 'pdf';
FILE: resources/js/types/time-entries.d.ts
type TimeEntriesGroupedByType (line 3) | type TimeEntriesGroupedByType = TimeEntry & { timeEntries: TimeEntry[] };
FILE: resources/js/utils/billing.ts
function isBillingActivated (line 4) | function isBillingActivated() {
function isInvoicingActivated (line 12) | function isInvoicingActivated() {
function isInTrial (line 20) | function isInTrial() {
function daysLeftInTrial (line 30) | function daysLeftInTrial() {
function isBlocked (line 42) | function isBlocked() {
function isFreePlan (line 52) | function isFreePlan() {
function hasActiveSubscription (line 56) | function hasActiveSubscription() {
function isAllowedToPerformPremiumAction (line 66) | function isAllowedToPerformPremiumAction() {
FILE: resources/js/utils/commandPaletteCommands.ts
type CommandGroup (line 29) | type CommandGroup =
type Command (line 38) | interface Command {
constant GROUP_PRIORITIES (line 51) | const GROUP_PRIORITIES: Record<CommandGroup, number> = {
function createNavigationCommands (line 61) | function createNavigationCommands(
function createTimerCommands (line 229) | function createTimerCommands(
function createActiveTimerCommands (line 284) | function createActiveTimerCommands(
function createThemeCommands (line 354) | function createThemeCommands(
function createCreateCommands (line 388) | function createCreateCommands(
function createOrganizationCommands (line 458) | function createOrganizationCommands(
function scoreEntity (line 478) | function scoreEntity(name: string, query: string, baseScore: number): nu...
FILE: resources/js/utils/feedback.ts
function openFeedback (line 1) | function openFeedback(): void {
FILE: resources/js/utils/fetchAllPages.ts
function fetchAllPages (line 6) | async function fetchAllPages<T>(
FILE: resources/js/utils/format.ts
function capitalizeFirstLetter (line 1) | function capitalizeFirstLetter(string: string) {
FILE: resources/js/utils/init.ts
function initializeStores (line 3) | function initializeStores() {
FILE: resources/js/utils/money.ts
function getOrganizationCurrencyString (line 13) | function getOrganizationCurrencyString() {
FILE: resources/js/utils/notification.ts
type NotificationType (line 7) | type NotificationType = 'success' | 'error';
function addNotification (line 21) | function addNotification(type: NotificationType, title: string, message?...
function removeNotification (line 30) | function removeNotification(uuid: string) {
function handleApiRequestNotifications (line 37) | async function handleApiRequestNotifications<T>(
FILE: resources/js/utils/permissions.ts
function currentUserHasPermission (line 9) | function currentUserHasPermission(permission: string) {
function canUpdateOrganization (line 16) | function canUpdateOrganization() {
function canViewProjects (line 20) | function canViewProjects() {
function canCreateProjects (line 24) | function canCreateProjects() {
function canUpdateProjects (line 28) | function canUpdateProjects() {
function canDeleteProjects (line 32) | function canDeleteProjects() {
function canViewProjectMembers (line 36) | function canViewProjectMembers() {
function canCreateTasks (line 40) | function canCreateTasks() {
function canUpdateTasks (line 44) | function canUpdateTasks() {
function canDeleteTasks (line 48) | function canDeleteTasks() {
function canCreateClients (line 52) | function canCreateClients() {
function canUpdateClients (line 56) | function canUpdateClients() {
function canDeleteClients (line 60) | function canDeleteClients() {
function canViewClients (line 64) | function canViewClients() {
function canViewMembers (line 68) | function canViewMembers() {
function canUpdateMembers (line 72) | function canUpdateMembers() {
function canDeleteMembers (line 76) | function canDeleteMembers() {
function canMergeMembers (line 80) | function canMergeMembers() {
function canMakeMembersPlaceholders (line 84) | function canMakeMembersPlaceholders() {
function canInvitePlaceholderMembers (line 88) | function canInvitePlaceholderMembers() {
function canCreateInvitations (line 92) | function canCreateInvitations() {
function canViewTags (line 96) | function canViewTags() {
function canCreateTags (line 100) | function canCreateTags() {
function canUpdateTags (line 104) | function canUpdateTags() {
function canDeleteTags (line 108) | function canDeleteTags() {
function canManageBilling (line 112) | function canManageBilling() {
function canViewReport (line 116) | function canViewReport() {
function canUpdateReport (line 119) | function canUpdateReport() {
function canDeleteReport (line 122) | function canDeleteReport() {
function canViewAllTimeEntries (line 126) | function canViewAllTimeEntries() {
function canViewInvoices (line 129) | function canViewInvoices() {
function canCreateReports (line 132) | function canCreateReports() {
FILE: resources/js/utils/prefetch.ts
function prefetchDashboard (line 85) | function prefetchDashboard(queryClient: QueryClient) {
function prefetchProjects (line 156) | function prefetchProjects(queryClient: QueryClient) {
function prefetchTasks (line 167) | function prefetchTasks(queryClient: QueryClient) {
function prefetchTags (line 178) | function prefetchTags(queryClient: QueryClient) {
function prefetchClients (line 189) | function prefetchClients(queryClient: QueryClient) {
function prefetchMembers (line 200) | function prefetchMembers(queryClient: QueryClient) {
function prefetchReports (line 211) | function prefetchReports(queryClient: QueryClient) {
function prefetchTimeEntries (line 222) | function prefetchTimeEntries(queryClient: QueryClient) {
function prefetchCalendarTimeEntries (line 244) | function prefetchCalendarTimeEntries(queryClient: QueryClient) {
function prefetchProjectMembers (line 260) | function prefetchProjectMembers(queryClient: QueryClient, projectId: str...
function findPrefetcher (line 277) | function findPrefetcher(url: string): ((queryClient: QueryClient) => voi...
function setupPrefetching (line 304) | function setupPrefetching(queryClient: QueryClient) {
FILE: resources/js/utils/roles.ts
function filterRoles (line 3) | function filterRoles(roles: Role[]) {
FILE: resources/js/utils/session.ts
function fetchToken (line 3) | async function fetchToken() {
function isTokenValid (line 13) | function isTokenValid() {
FILE: resources/js/utils/theme.ts
type themeOption (line 4) | type themeOption = 'system' | 'light' | 'dark';
function useTheme (line 18) | function useTheme() {
FILE: resources/js/utils/useAggregatedTimeEntriesQuery.ts
function useAggregatedTimeEntriesQuery (line 10) | function useAggregatedTimeEntriesQuery(
FILE: resources/js/utils/useClients.ts
function createClient (line 12) | async function createClient(clientBody: CreateClientBody): Promise<Clien...
function updateClient (line 30) | async function updateClient(clientId: string, clientBody: UpdateClientBo...
function deleteClient (line 48) | async function deleteClient(clientId: string) {
FILE: resources/js/utils/useClientsQuery.ts
function fetchAllClients (line 8) | async function fetchAllClients(organizationId: string): Promise<Client[]> {
function useClientsQuery (line 17) | function useClientsQuery() {
FILE: resources/js/utils/useCommandPalette.ts
constant GROUP_CONFIG (line 75) | const GROUP_CONFIG: { id: CommandGroupType; heading: string }[] = [
constant ENTITY_BADGE_CLASSES (line 85) | const ENTITY_BADGE_CLASSES: Record<string, string> = {
constant ENTITY_ICONS (line 94) | const ENTITY_ICONS: Record<string, typeof FolderIcon> = {
function useCommandPalette (line 102) | function useCommandPalette() {
FILE: resources/js/utils/useCssVariable.ts
function useCssVariable (line 3) | function useCssVariable(variableName: string) {
FILE: resources/js/utils/useCurrentTimeEntry.ts
function $reset (line 41) | function $reset() {
function startLiveTimer (line 48) | function startLiveTimer() {
function stopLiveTimer (line 56) | function stopLiveTimer() {
function fetchCurrentTimeEntry (line 62) | async function fetchCurrentTimeEntry() {
function startTimer (line 102) | async function startTimer() {
function stopTimer (line 136) | async function stopTimer() {
function updateTimer (line 164) | async function updateTimer() {
function setActiveState (line 216) | async function setActiveState(newState: boolean) {
FILE: resources/js/utils/useInvitations.ts
function fetchAllInvitations (line 9) | async function fetchAllInvitations(organizationId: string): Promise<Invi...
function fetchInvitations (line 22) | async function fetchInvitations() {
function createInvitation (line 36) | async function createInvitation(inviteBody: CreateInvitationBody): Promi...
FILE: resources/js/utils/useMembers.ts
type MemberBillableKey (line 8) | type MemberBillableKey = 'default-rate' | 'custom-rate';
function removeMember (line 14) | async function removeMember(membershipId: string) {
function updateMember (line 32) | async function updateMember(memberId: string, memberBody: UpdateMemberBo...
FILE: resources/js/utils/useMembersQuery.ts
function fetchAllMembers (line 8) | async function fetchAllMembers(organizationId: string): Promise<Member[]> {
function useMembersQuery (line 17) | function useMembersQuery() {
FILE: resources/js/utils/useOrganization.ts
function switchOrganization (line 14) | function switchOrganization(organizationId: string) {
function fetchOrganization (line 37) | async function fetchOrganization() {
function updateOrganization (line 53) | async function updateOrganization(organizationBody: UpdateOrganizationBo...
FILE: resources/js/utils/useOrganizationQuery.ts
function useOrganizationQuery (line 5) | function useOrganizationQuery(organizationId: string) {
FILE: resources/js/utils/useProjectMembers.ts
function createProjectMember (line 12) | async function createProjectMember(
function updateProjectMember (line 35) | async function updateProjectMember(
function deleteProjectMember (line 60) | async function deleteProjectMember(projectId: string, projectMemberId: s...
FILE: resources/js/utils/useProjectMembersQuery.ts
function fetchAllProjectMembers (line 8) | async function fetchAllProjectMembers(
function useProjectMembersQuery (line 20) | function useProjectMembersQuery(projectId: Ref<string | null> | string) {
FILE: resources/js/utils/useProjects.ts
function createProject (line 12) | async function createProject(projectBody: CreateProjectBody) {
function deleteProject (line 32) | async function deleteProject(projectId: string) {
function updateProject (line 50) | async function updateProject(projectId: string, updateProjectBody: Updat...
FILE: resources/js/utils/useProjectsQuery.ts
function fetchAllProjects (line 8) | async function fetchAllProjects(organizationId: string): Promise<Project...
function useProjectsQuery (line 17) | function useProjectsQuery() {
FILE: resources/js/utils/useReporting.ts
type GroupingOption (line 13) | type GroupingOption =
function getNameForReportingRowEntry (line 40) | function getNameForReportingRowEntry(key: string | null, type: string | ...
FILE: resources/js/utils/useReportsQuery.ts
function fetchAllReports (line 5) | async function fetchAllReports(organizationId: string): Promise<Report[]> {
FILE: resources/js/utils/useTags.ts
function deleteTag (line 12) | async function deleteTag(tagId: string) {
function createTag (line 30) | async function createTag(name: string): Promise<Tag | undefined> {
FILE: resources/js/utils/useTagsQuery.ts
function fetchAllTags (line 8) | async function fetchAllTags(organizationId: string): Promise<Tag[]> {
function useTagsQuery (line 17) | function useTagsQuery() {
FILE: resources/js/utils/useTasks.ts
function updateTask (line 12) | async function updateTask(taskId: string, taskBody: UpdateTaskBody) {
function createTask (line 30) | async function createTask(task: CreateTaskBody) {
function deleteTask (line 47) | async function deleteTask(taskId: string) {
FILE: resources/js/utils/useTasksQuery.ts
function fetchAllTasks (line 8) | async function fetchAllTasks(organizationId: string): Promise<Task[]> {
function useTasksQuery (line 17) | function useTasksQuery() {
FILE: resources/js/utils/useTimeEntriesCalendarQuery.ts
function getExpandedCalendarDateRange (line 22) | function getExpandedCalendarDateRange(
function getInitialWeekRange (line 49) | function getInitialWeekRange(): { start: Date; end: Date } {
function createCalendarQueryKey (line 69) | function createCalendarQueryKey(
function fetchAllCalendarEntries (line 84) | async function fetchAllCalendarEntries(
function useTimeEntriesCalendarQuery (line 117) | function useTimeEntriesCalendarQuery(
FILE: resources/js/utils/useTimeEntriesInfiniteQuery.ts
function useTimeEntriesInfiniteQuery (line 7) | function useTimeEntriesInfiniteQuery() {
FILE: resources/js/utils/useTimeEntriesMutations.ts
function useTimeEntriesMutations (line 11) | function useTimeEntriesMutations() {
FILE: resources/js/utils/useTimeEntriesReportQuery.ts
function useTimeEntriesReportQuery (line 6) | function useTimeEntriesReportQuery(
FILE: resources/js/utils/useUser.ts
function getCurrentUserId (line 9) | function getCurrentUserId() {
function getCurrentUser (line 13) | function getCurrentUser() {
function getCurrentOrganizationId (line 17) | function getCurrentOrganizationId() {
function getCurrentMembershipId (line 21) | function getCurrentMembershipId() {
function getCurrentRole (line 26) | function getCurrentRole() {
FILE: resources/js/ziggy.d.ts
type RouteList (line 3) | interface RouteList {
FILE: tests/CreatesApplication.php
type CreatesApplication (line 10) | trait CreatesApplication
method createApplication (line 15) | public function createApplication(): Application
FILE: tests/Feature/AuthenticationTest.php
class AuthenticationTest (line 12) | class AuthenticationTest extends TestCase
method test_login_screen_can_be_rendered (line 16) | public function test_login_screen_can_be_rendered(): void
method test_users_can_authenticate_using_the_login_screen (line 23) | public function test_users_can_authenticate_using_the_login_screen(): ...
method test_users_can_not_authenticate_with_invalid_password (line 36) | public function test_users_can_not_authenticate_with_invalid_password(...
FILE: tests/Feature/BrowserSessionsTest.php
class BrowserSessionsTest (line 11) | class BrowserSessionsTest extends TestCase
method test_other_browser_sessions_can_be_logged_out (line 15) | public function test_other_browser_sessions_can_be_logged_out(): void
FILE: tests/Feature/CreateOrganizationTest.php
class CreateOrganizationTest (line 16) | class CreateOrganizationTest extends TestCase
method test_organizations_can_be_created (line 20) | public function test_organizations_can_be_created(): void
FILE: tests/Feature/DeleteAccountTest.php
class DeleteAccountTest (line 14) | class DeleteAccountTest extends TestCase
method test_user_accounts_can_be_deleted (line 18) | public function test_user_accounts_can_be_deleted(): void
method test_correct_password_must_be_provided_before_account_can_be_deleted (line 34) | public function test_correct_password_must_be_provided_before_account_...
method test_user_account_can_not_be_deleted_if_attached_to_a_organization_with_multiple_users (line 49) | public function test_user_account_can_not_be_deleted_if_attached_to_a_...
FILE: tests/Feature/DeleteOrganizationTest.php
class DeleteOrganizationTest (line 14) | class DeleteOrganizationTest extends TestCase
method test_organizations_can_be_deleted_and_users_of_the_organization_that_have_no_organization_get_a_new_one (line 18) | public function test_organizations_can_be_deleted_and_users_of_the_org...
method test_personal_organizations_can_be_deleted_but_user_gets_an_new_one_if_this_is_the_only_one_left (line 43) | public function test_personal_organizations_can_be_deleted_but_user_ge...
method test_organization_can_not_be_deleted_if_user_is_not_owner (line 61) | public function test_organization_can_not_be_deleted_if_user_is_not_ow...
FILE: tests/Feature/EmailVerificationTest.php
class EmailVerificationTest (line 16) | class EmailVerificationTest extends TestCase
method test_email_verification_screen_can_be_rendered (line 20) | public function test_email_verification_screen_can_be_rendered(): void
method test_email_can_be_verified (line 33) | public function test_email_can_be_verified(): void
method test_email_can_not_verified_with_invalid_hash (line 59) | public function test_email_can_not_verified_with_invalid_hash(): void
FILE: tests/Feature/InviteTeamMemberTest.php
class InviteTeamMemberTest (line 16) | class InviteTeamMemberTest extends TestCase
method test_team_members_can_no_longer_be_invited_to_team_over_jetstream (line 20) | public function test_team_members_can_no_longer_be_invited_to_team_ove...
method test_team_member_invitations_can_no_longer_be_cancelled_over_jetstream (line 38) | public function test_team_member_invitations_can_no_longer_be_cancelle...
method test_team_member_invitations_can_be_accepted (line 58) | public function test_team_member_invitations_can_be_accepted(): void
method test_team_member_invitations_of_placeholder_can_be_accepted_and_migrates_date_to_real_user (line 85) | public function test_team_member_invitations_of_placeholder_can_be_acc...
method test_team_member_accept_fails_if_user_with_that_email_does_not_exist (line 123) | public function test_team_member_accept_fails_if_user_with_that_email_...
FILE: tests/Feature/LeaveTeamTest.php
class LeaveTeamTest (line 11) | class LeaveTeamTest extends TestCase
method test_users_can_no_longer_leave_team_over_jetstream (line 15) | public function test_users_can_no_longer_leave_team_over_jetstream(): ...
FILE: tests/Feature/PasswordConfirmationTest.php
class PasswordConfirmationTest (line 11) | class PasswordConfirmationTest extends TestCase
method test_confirm_password_screen_can_be_rendered (line 15) | public function test_confirm_password_screen_can_be_rendered(): void
method test_password_can_be_confirmed (line 24) | public function test_password_can_be_confirmed(): void
method test_password_is_not_confirmed_with_invalid_password (line 36) | public function test_password_is_not_confirmed_with_invalid_password()...
FILE: tests/Feature/PasswordResetTest.php
class PasswordResetTest (line 14) | class PasswordResetTest extends TestCase
method test_reset_password_link_screen_can_be_rendered (line 18) | public function test_reset_password_link_screen_can_be_rendered(): void
method test_reset_password_link_can_be_requested (line 29) | public function test_reset_password_link_can_be_requested(): void
method test_reset_password_screen_can_be_rendered (line 46) | public function test_reset_password_screen_can_be_rendered(): void
method test_password_can_be_reset_with_valid_token (line 69) | public function test_password_can_be_reset_with_valid_token(): void
FILE: tests/Feature/ProfileInformationTest.php
class ProfileInformationTest (line 13) | class ProfileInformationTest extends TestCase
method test_show_profile_information_succeeds (line 17) | public function test_show_profile_information_succeeds(): void
method test_profile_information_can_be_updated (line 30) | public function test_profile_information_can_be_updated(): void
FILE: tests/Feature/RegistrationTest.php
class RegistrationTest (line 22) | class RegistrationTest extends TestCase
method test_registration_screen_can_be_rendered (line 26) | public function test_registration_screen_can_be_rendered(): void
method test_new_users_can_register (line 37) | public function test_new_users_can_register(): void
method test_user_registration_fails_if_registration_is_deactivated (line 67) | public function test_user_registration_fails_if_registration_is_deacti...
method test_new_user_can_not_register_with_likely_invalid_domain (line 92) | public function test_new_user_can_not_register_with_likely_invalid_dom...
method test_new_user_can_register_with_uppercase_email (line 107) | public function test_new_user_can_register_with_uppercase_email(): void
method test_new_users_can_consent_to_newsletter_during_registration (line 122) | public function test_new_users_can_consent_to_newsletter_during_regist...
method test_new_users_can_register_and_frontend_can_send_timezone_for_user (line 149) | public function test_new_users_can_register_and_frontend_can_send_time...
method test_new_users_can_register_and_uses_ip_lookup_service_to_get_information_about_currency_and_start_of_week (line 168) | public function test_new_users_can_register_and_uses_ip_lookup_service...
method test_new_users_can_register_and_uses_ip_lookup_service_to_get_information_about_timezone_if_client_did_not_send_one (line 199) | public function test_new_users_can_register_and_uses_ip_lookup_service...
method test_new_users_can_register_and_uses_ip_lookup_service_to_get_information_about_timezone_if_client_sends_invalid_one (line 230) | public function test_new_users_can_register_and_uses_ip_lookup_service...
method test_new_users_can_register_and_legacy_timezone_from_client_is_mapped_to_new_timezone (line 261) | public function test_new_users_can_register_and_legacy_timezone_from_c...
method test_new_users_can_register_and_ignores_invalid_timezones_from_frontend (line 292) | public function test_new_users_can_register_and_ignores_invalid_timezo...
method test_new_users_can_not_register_if_user_with_email_already_exists (line 309) | public function test_new_users_can_not_register_if_user_with_email_alr...
method test_new_users_can_register_if_placeholder_user_with_email_already_exists (line 329) | public function test_new_users_can_register_if_placeholder_user_with_e...
FILE: tests/Feature/RemoveTeamMemberTest.php
class RemoveTeamMemberTest (line 11) | class RemoveTeamMemberTest extends TestCase
method test_team_members_can_no_longer_be_removed_from_teams_over_jetstream_endpoints (line 15) | public function test_team_members_can_no_longer_be_removed_from_teams_...
FILE: tests/Feature/TwoFactorAuthenticationSettingsTest.php
class TwoFactorAuthenticationSettingsTest (line 12) | class TwoFactorAuthenticationSettingsTest extends TestCase
method test_two_factor_authentication_can_be_enabled (line 16) | public function test_two_factor_authentication_can_be_enabled(): void
method test_recovery_codes_can_be_regenerated (line 32) | public function test_recovery_codes_can_be_regenerated(): void
method test_two_factor_authentication_can_be_disabled (line 53) | public function test_two_factor_authentication_can_be_disabled(): void
FILE: tests/Feature/UpdatePasswordTest.php
class UpdatePasswordTest (line 12) | class UpdatePasswordTest extends TestCase
method test_password_can_be_updated (line 16) | public function test_password_can_be_updated(): void
method test_current_password_must_be_correct (line 29) | public function test_current_password_must_be_correct(): void
method test_new_passwords_must_match (line 44) | public function test_new_passwords_must_match(): void
FILE: tests/Feature/UpdateTeamMemberRoleTest.php
class UpdateTeamMemberRoleTest (line 12) | class UpdateTeamMemberRoleTest extends TestCase
method test_team_member_roles_can_no_longer_be_updated_over_jetstream (line 16) | public function test_team_member_roles_can_no_longer_be_updated_over_j...
FILE: tests/Feature/UpdateTeamTest.php
class UpdateTeamTest (line 11) | class UpdateTeamTest extends TestCase
method test_team_update_page_shows_not_found_if_id_is_not_uuid (line 15) | public function test_team_update_page_shows_not_found_if_id_is_not_uui...
method test_team_names_can_be_updated (line 28) | public function test_team_names_can_be_updated(): void
FILE: tests/TestCase.php
class TestCase (line 20) | abstract class TestCase extends BaseTestCase
method setUp (line 26) | protected function setUp(): void
method mockPrivateStorage (line 39) | protected function mockPrivateStorage(): void
method mockPublicStorage (line 44) | protected function mockPublicStorage(): void
method tearDown (line 49) | protected function tearDown(): void
method assertEqualsIdsOfEloquentCollection (line 56) | protected function assertEqualsIdsOfEloquentCollection(array $ids, Col...
method travelTo (line 69) | public function travelTo($date, $callback = null): void
method assertBillableRateServiceIsUnused (line 74) | protected function assertBillableRateServiceIsUnused(): void
method actAsOrganizationWithSubscription (line 84) | protected function actAsOrganizationWithSubscription(): void
method actAsOrganizationWithoutSubscriptionAndWithoutTrial (line 94) | protected function actAsOrganizationWithoutSubscriptionAndWithoutTrial...
FILE: tests/TestCaseWithDatabase.php
class TestCaseWithDatabase (line 16) | abstract class TestCaseWithDatabase extends TestCase
method createUserWithPermission (line 24) | protected function createUserWithPermission(array $permissions = [], b...
method createUserWithRole (line 59) | public function createUserWithRole(Role $role, bool $employeesCanSeeBi...
method enableQueryLog (line 87) | protected function enableQueryLog(): void
method getQueryLog (line 93) | protected function getQueryLog(): array
method assertQueryCount (line 102) | protected function assertQueryCount(int $count, string $message = ''):...
FILE: tests/Unit/Console/Commands/Admin/OrganizationDeleteCommandTest.php
class OrganizationDeleteCommandTest (line 15) | #[CoversClass(OrganizationDeleteCommand::class)]
method test_it_calls_the_deletion_service_with_the_organization (line 18) | public function test_it_calls_the_deletion_service_with_the_organizati...
method test_it_fails_if_organization_does_not_exist (line 37) | public function test_it_fails_if_organization_does_not_exist(): void
method test_it_fails_if_organization_id_is_not_a_valid_uuid (line 50) | public function test_it_fails_if_organization_id_is_not_a_valid_uuid()...
FILE: tests/Unit/Console/Commands/Admin/UserCreateCommandCommandTest.php
class UserCreateCommandCommandTest (line 15) | #[CoversClass(UserCreateCommand::class)]
method test_it_creates_user (line 18) | public function test_it_creates_user(): void
method test_created_user_is_verified_if_option_is_set (line 41) | public function test_created_user_is_verified_if_option_is_set(): void
method test_it_fails_if_user_with_email_already_exists (line 66) | public function test_it_fails_if_user_with_email_already_exists(): void
method test_it_asks_for_password_if_option_is_set (line 88) | public function test_it_asks_for_password_if_option_is_set(): void
FILE: tests/Unit/Console/Commands/Admin/UserVerifyCommandTest.php
class UserVerifyCommandTest (line 14) | #[CoversClass(UserVerifyCommand::class)]
method test_it_verifies_user_email (line 17) | public function test_it_verifies_user_email(): void
method test_it_fails_if_user_does_not_exist (line 35) | public function test_it_fails_if_user_does_not_exist(): void
method test_it_fails_if_user_email_is_already_verified (line 54) | public function test_it_fails_if_user_email_is_already_verified(): void
FILE: tests/Unit/Console/Commands/Auth/AuthSendReminderForExpiringApiTokensCommandTest.php
class AuthSendReminderForExpiringApiTokensCommandTest (line 19) | #[CoversClass(AuthSendReminderForExpiringApiTokensCommand::class)]
method test_sends_mail_for_expired_api_tokens_but_ignores_the_one_where_the_mail_was_already_sent_and_ignores_non_api_tokens (line 22) | public function test_sends_mail_for_expired_api_tokens_but_ignores_the...
method test_sends_mail_for_api_tokens_that_expire_soon_but_ignores_the_one_where_the_mail_was_already_sent_and_ignores_non_api_tokens (line 71) | public function test_sends_mail_for_api_tokens_that_expire_soon_but_ig...
FILE: tests/Unit/Console/Commands/Correction/CorrectionPlaceholderMembersCommandTest.php
class CorrectionPlaceholderMembersCommandTest (line 17) | #[CoversClass(CorrectionPlaceholderMembersCommand::class)]
method test_sets_member_role_to_placeholder_if_user_is_placeholder (line 20) | public function test_sets_member_role_to_placeholder_if_user_is_placeh...
method test_sets_member_role_to_placeholder_if_user_is_placeholder_dry_run (line 43) | public function test_sets_member_role_to_placeholder_if_user_is_placeh...
FILE: tests/Unit/Console/Commands/Report/ReportSetExpiredToPrivateCommandTest.php
class ReportSetExpiredToPrivateCommandTest (line 14) | #[CoversClass(ReportSetExpiredToPrivateCommand::class)]
method test_command_sets_expired_reports_to_private (line 17) | public function test_command_sets_expired_reports_to_private(): void
method test_command_sets_expired_reports_to_private_in_dry_run_mode (line 69) | public function test_command_sets_expired_reports_to_private_in_dry_ru...
FILE: tests/Unit/Console/Commands/SelfHost/SelfHostCheckForUpdateCommandTest.php
class SelfHostCheckForUpdateCommandTest (line 17) | #[CoversClass(SelfHostCheckForUpdateCommand::class)]
method test_checks_for_update_and_saves_version_in_cache (line 21) | public function test_checks_for_update_and_saves_version_in_cache(): void
method test_checks_for_update_fails_gracefully_if_response_has_error_status_code (line 37) | public function test_checks_for_update_fails_gracefully_if_response_ha...
method test_checks_for_update_fails_gracefully_if_timeout_happens (line 53) | public function test_checks_for_update_fails_gracefully_if_timeout_hap...
FILE: tests/Unit/Console/Commands/SelfHost/SelfHostDatabaseConsistencyCommandTest.php
class SelfHostDatabaseConsistencyCommandTest (line 20) | #[CoversClass(SelfHostDatabaseConsistency::class)]
method test_checks_that_task_need_to_be_part_of_project_in_time_entries (line 23) | public function test_checks_that_task_need_to_be_part_of_project_in_ti...
method test_checks_that_client_id_is_the_client_id_of_the_project (line 41) | public function test_checks_that_client_id_is_the_client_id_of_the_pro...
method test_checks_that_client_id_is_the_client_id_of_the_project_with_no_client_in_time_entry (line 61) | public function test_checks_that_client_id_is_the_client_id_of_the_pro...
method test_checks_that_client_id_is_only_null_if_project_is_also_null (line 81) | public function test_checks_that_client_id_is_only_null_if_project_is_...
method test_checks_that_every_user_needs_to_be_a_member_of_at_least_one_organization (line 100) | public function test_checks_that_every_user_needs_to_be_a_member_of_at...
method test_checks_that_every_organization_needs_at_least_an_owner (line 114) | public function test_checks_that_every_organization_needs_at_least_an_...
method test_checks_that_every_member_can_only_have_one_running_time_entry (line 129) | public function test_checks_that_every_member_can_only_have_one_runnin...
method test_checks_that_users_have_a_current_organization_that_they_are_not_a_member_of (line 145) | public function test_checks_that_users_have_a_current_organization_tha...
FILE: tests/Unit/Console/Commands/SelfHost/SelfHostGenerateKeysCommandTest.php
class SelfHostGenerateKeysCommandTest (line 13) | #[CoversClass(SelfHostGenerateKeysCommand::class)]
method test_generates_app_key_and_passport_keys_per_default_in_env_format (line 16) | public function test_generates_app_key_and_passport_keys_per_default_i...
method test_generates_app_key_and_passport_keys_in_env_format_in_multiline_if_requested (line 31) | public function test_generates_app_key_and_passport_keys_in_env_format...
method test_generates_app_key_and_passport_keys_in_yaml_format_if_requested (line 46) | public function test_generates_app_key_and_passport_keys_in_yaml_forma...
method test_generates_app_fail_if_attribute_format_is_invalid (line 61) | public function test_generates_app_fail_if_attribute_format_is_invalid...
FILE: tests/Unit/Console/Commands/SelfHost/SelfHostTelemetryCommandTest.php
class SelfHostTelemetryCommandTest (line 16) | #[CoversClass(SelfHostTelemetryCommand::class)]
method test_telemetry_sends_data_to_telemetry_endpoint_of_solidtime_cloud (line 20) | public function test_telemetry_sends_data_to_telemetry_endpoint_of_sol...
method test_telemetry_sends_fails_gracefully_if_response_has_error_status_code (line 36) | public function test_telemetry_sends_fails_gracefully_if_response_has_...
method test_telemetry_sends_fails_gracefully_if_timeout_happens (line 52) | public function test_telemetry_sends_fails_gracefully_if_timeout_happe...
FILE: tests/Unit/Console/Commands/TimeEntry/TimeEntrySendStillRunningMailsCommandTest.php
class TimeEntrySendStillRunningMailsCommandTest (line 17) | #[CoversClass(TimeEntrySendStillRunningMailsCommand::class)]
method test_sends_mails_for_still_running_time_entries (line 20) | public function test_sends_mails_for_still_running_time_entries(): void
method test_does_not_send_emails_for_not_running_time_entries (line 48) | public function test_does_not_send_emails_for_not_running_time_entries...
method test_does_not_send_emails_for_running_time_entries_that_are_short_than_the_threshold (line 70) | public function test_does_not_send_emails_for_running_time_entries_tha...
method test_does_not_send_emails_for_running_time_entries_that_are_longer_than_the_threshold_but_already_received_the_email (line 92) | public function test_does_not_send_emails_for_running_time_entries_tha...
method test_dry_run_option_does_not_send_mails_but_outputs_what_would_happen (line 115) | public function test_dry_run_option_does_not_send_mails_but_outputs_wh...
method test_does_not_send_emails_for_placeholder_users (line 139) | public function test_does_not_send_emails_for_placeholder_users(): void
FILE: tests/Unit/Console/KernelTest.php
class KernelTest (line 11) | #[CoversClass(Kernel::class)]
method test_self_host_commands_schedule_time_is_consistent_with_app_key (line 14) | public function test_self_host_commands_schedule_time_is_consistent_wi...
method test_self_hosting_telemetry_can_be_activated (line 51) | public function test_self_hosting_telemetry_can_be_activated(): void
method test_self_hosting_telemetry_can_be_deactivated (line 67) | public function test_self_hosting_telemetry_can_be_deactivated(): void
method test_self_hosting_check_for_update_can_be_activated (line 83) | public function test_self_hosting_check_for_update_can_be_activated():...
method test_self_hosting_check_for_update_can_be_deactivated (line 99) | public function test_self_hosting_check_for_update_can_be_deactivated(...
FILE: tests/Unit/Database/MigrationTest.php
class MigrationTest (line 10) | class MigrationTest extends TestCase
method test_fresh_migration_and_rollback_runs_successfully (line 14) | public function test_fresh_migration_and_rollback_runs_successfully():...
FILE: tests/Unit/Database/SeederTest.php
class SeederTest (line 11) | class SeederTest extends TestCase
method test_running_the_seeder_multiple_times_runs_successfully (line 15) | public function test_running_the_seeder_multiple_times_runs_successful...
method test_fresh_migration_with_seeder_and_rollback_runs_successfully (line 24) | public function test_fresh_migration_with_seeder_and_rollback_runs_suc...
method setupForSeeder (line 33) | private function setupForSeeder(): void
FILE: tests/Unit/Endpoint/Api/V1/ApiEndpointTestAbstract.php
class ApiEndpointTestAbstract (line 10) | class ApiEndpointTestAbstract extends TestCaseWithDatabase
method assertResponseCode (line 12) | protected function assertResponseCode(TestResponse $response, int $sta...
FILE: tests/Unit/Endpoint/Api/V1/ApiTokenEndpointTest.php
class ApiTokenEndpointTest (line 14) | #[UsesClass(ApiTokenController::class)]
method test_index_endpoint_returns_list_api_tokens (line 17) | public function test_index_endpoint_returns_list_api_tokens(): void
method test_index_endpoint_returns_api_tokens_ordered_by_created_at_descending (line 49) | public function test_index_endpoint_returns_api_tokens_ordered_by_crea...
method test_store_endpoint_creates_new_api_token (line 74) | public function test_store_endpoint_creates_new_api_token(): void
method test_store_fails_if_personal_access_client_is_not_configured (line 101) | public function test_store_fails_if_personal_access_client_is_not_conf...
method test_revoke_endpoint_revokes_api_token (line 121) | public function test_revoke_endpoint_revokes_api_token(): void
method test_revoke_fails_if_token_is_not_personal_access_token (line 140) | public function test_revoke_fails_if_token_is_not_personal_access_toke...
method test_revoke_fails_if_token_with_id_does_not_exist (line 160) | public function test_revoke_fails_if_token_with_id_does_not_exist(): void
method test_revoke_fails_if_the_token_does_not_belong_to_the_user (line 173) | public function test_revoke_fails_if_the_token_does_not_belong_to_the_...
method test_destroy_endpoint_deletes_api_token (line 193) | public function test_destroy_endpoint_deletes_api_token(): void
method test_destroy_fails_if_token_is_not_personal_access_token (line 209) | public function test_destroy_fails_if_token_is_not_personal_access_tok...
method test_destroy_fails_if_token_with_id_does_not_exist (line 228) | public function test_destroy_fails_if_token_with_id_does_not_exist(): ...
method test_destroy_fails_if_the_token_does_not_belong_to_the_user (line 241) | public function test_destroy_fails_if_the_token_does_not_belong_to_the...
method createPersonalAccessClient (line 260) | private function createPersonalAccessClient(): Client
method createClient (line 269) | private function createClient(): Client
FILE: tests/Unit/Endpoint/Api/V1/ChartEndpointTest.php
class ChartEndpointTest (line 11) | class ChartEndpointTest extends EndpointTestAbstract
method test_weekly_project_overview_endpoint_fails_if_user_has_no_permission_to_view_chart (line 13) | public function test_weekly_project_overview_endpoint_fails_if_user_ha...
method test_weekly_project_overview_endpoint_returns_chart_data (line 28) | public function test_weekly_project_overview_endpoint_returns_chart_da...
method test_latest_tasks_endpoint_fails_if_user_has_no_permission_to_view_chart (line 43) | public function test_latest_tasks_endpoint_fails_if_user_has_no_permis...
method test_latest_tasks_endpoint_returns_chart_data (line 58) | public function test_latest_tasks_endpoint_returns_chart_data(): void
method test_last_seven_days_endpoint_fails_if_user_has_no_permission_to_view_chart (line 73) | public function test_last_seven_days_endpoint_fails_if_user_has_no_per...
method test_last_seven_days_endpoint_returns_chart_data (line 88) | public function test_last_seven_days_endpoint_returns_chart_data(): void
method test_latest_team_activity_endpoint_fails_if_user_has_no_permission_to_view_chart_for_the_whole_orgnaization (line 103) | public function test_latest_team_activity_endpoint_fails_if_user_has_n...
method test_latest_team_activity_endpoint_returns_chart_data (line 118) | public function test_latest_team_activity_endpoint_returns_chart_data(...
method test_daily_tracked_hours_endpoint_fails_if_user_has_no_permission_to_view_chart (line 133) | public function test_daily_tracked_hours_endpoint_fails_if_user_has_no...
method test_daily_tracked_hours_endpoint_returns_chart_data (line 148) | public function test_daily_tracked_hours_endpoint_returns_chart_data()...
method test_total_weekly_time_endpoint_fails_if_user_has_no_permission_to_view_chart (line 163) | public function test_total_weekly_time_endpoint_fails_if_user_has_no_p...
method test_total_weekly_time_endpoint_returns_chart_data (line 178) | public function test_total_weekly_time_endpoint_returns_chart_data(): ...
method test_total_weekly_billable_time_endpoint_fails_if_user_has_no_permission_to_view_chart (line 193) | public function test_total_weekly_billable_time_endpoint_fails_if_user...
method test_total_weekly_billable_time_endpoint_returns_chart_data (line 208) | public function test_total_
Condensed preview — 1208 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (4,313K chars).
[
{
"path": ".editorconfig",
"chars": 258,
"preview": "root = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_size = 4\nindent_style = space\ninsert_final_newline = true\ntrim_"
},
{
"path": ".gitattributes",
"chars": 186,
"preview": "* text=auto eol=lf\n\n*.blade.php diff=html\n*.css diff=css\n*.html diff=html\n*.md diff=markdown\n*.php diff=php\n\n/.github ex"
},
{
"path": ".github/FUNDING.yml",
"chars": 21,
"preview": "github: solidtime-io\n"
},
{
"path": ".github/ISSUE_TEMPLATE/1_bug_report.yml",
"chars": 1133,
"preview": "name: Bug Report\ndescription: \"Report a bug\"\nbody:\n - type: markdown\n attributes:\n value: |\n Before crea"
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 353,
"preview": "blank_issues_enabled: false\ncontact_links:\n - name: 🚀 Feature Request\n url: https://github.com/solidtime-io/solidtim"
},
{
"path": ".github/PULL_REQUEST_TEMPLATE.md",
"chars": 554,
"preview": "## What does this PR do?\n\n<!-- Please include a summary of the change and which issue is fixed. Please also include rele"
},
{
"path": ".github/dependabot.yml",
"chars": 1049,
"preview": "version: 2\nupdates:\n - package-ecosystem: \"github-actions\"\n directory: \"/\"\n schedule:\n interval: \"daily\"\n "
},
{
"path": ".github/workflows/build-onpremise.yml",
"chars": 6725,
"preview": "on:\n push:\n branches:\n - main\n - develop\n tags:\n - '*'\n pull_request:\n paths:\n - '.github"
},
{
"path": ".github/workflows/build-private.yml",
"chars": 6472,
"preview": "on:\n push:\n branches:\n - main\n - develop\n tags:\n - '*'\n pull_request:\n paths:\n - '.github"
},
{
"path": ".github/workflows/build-public.yml",
"chars": 6722,
"preview": "on:\n push:\n branches:\n - main\n - develop\n tags:\n - '*'\n pull_request:\n paths:\n - '.github"
},
{
"path": ".github/workflows/generate-api-docs.yml",
"chars": 1739,
"preview": "name: Generate API docs\non:\n push:\n branches:\n - main\npermissions:\n contents: read\n\njobs:\n api_docs:\n runs"
},
{
"path": ".github/workflows/npm-build.yml",
"chars": 699,
"preview": "name: NPM Build\n\non: [push]\npermissions:\n contents: read\n\njobs:\n build:\n runs-on: ubuntu-latest\n timeout-minutes"
},
{
"path": ".github/workflows/npm-format-check.yml",
"chars": 430,
"preview": "name: NPM Format Check\n\non: [push]\n\njobs:\n format-check:\n runs-on: ubuntu-latest\n timeout-minutes: 10\n\n steps:"
},
{
"path": ".github/workflows/npm-lint.yml",
"chars": 426,
"preview": "name: NPM Lint\n\non: [push]\npermissions:\n contents: read\n\njobs:\n build:\n runs-on: ubuntu-latest\n timeout-minutes:"
},
{
"path": ".github/workflows/npm-publish-api.yml",
"chars": 934,
"preview": "name: Publish API package to NPM\non:\n workflow_dispatch\npermissions:\n contents: read\njobs:\n build:\n runs-on: ubunt"
},
{
"path": ".github/workflows/npm-publish-ui.yml",
"chars": 938,
"preview": "name: Publish UI package to NPM\non:\n workflow_dispatch\npermissions:\n contents: read\njobs:\n build:\n runs-on: ubuntu"
},
{
"path": ".github/workflows/npm-typecheck.yml",
"chars": 716,
"preview": "name: NPM Typecheck\n\non: [push]\npermissions:\n contents: read\njobs:\n build:\n runs-on: ubuntu-latest\n timeout-minu"
},
{
"path": ".github/workflows/phpstan.yml",
"chars": 625,
"preview": "name: Static code analysis (PHPStan)\non: push\npermissions:\n contents: read\njobs:\n phpstan:\n runs-on: ubuntu-latest\n"
},
{
"path": ".github/workflows/phpunit.yml",
"chars": 1980,
"preview": "name: PHPUnit Tests\non: push\npermissions:\n contents: read\njobs:\n phpunit:\n runs-on: ubuntu-latest\n timeout-minut"
},
{
"path": ".github/workflows/pint.yml",
"chars": 328,
"preview": "name: PHP Linting\non: push\npermissions:\n contents: read\njobs:\n pint:\n runs-on: ubuntu-latest\n timeout-minutes: 1"
},
{
"path": ".github/workflows/playwright.yml",
"chars": 3457,
"preview": "name: Playwright Tests\non: [push]\npermissions:\n contents: read\njobs:\n test:\n runs-on: ubuntu-latest\n timeout-min"
},
{
"path": ".gitignore",
"chars": 601,
"preview": "/.phpunit.cache\nnode_modules\ndist\n/public/build\n/public/hot\n/public/storage\n/public/css\n/public/js\n/public/vendor\n/lang/"
},
{
"path": ".prettierignore",
"chars": 326,
"preview": "# Ignore build outputs\nnode_modules/\nvendor/\nstorage/\nbootstrap/cache/\npublic/build/\npublic/hot/\n\n# Ignore lock files\npa"
},
{
"path": ".prettierrc.json",
"chars": 157,
"preview": "{\n \"trailingComma\": \"es5\",\n \"tabWidth\": 4,\n \"singleQuote\": true,\n \"bracketSameLine\": true,\n \"quoteProps\":"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 2045,
"preview": "# Code of Conduct\n\nThe goal is to create a community that is open and welcoming to all individuals.\nTo achieve this, we "
},
{
"path": "CONTRIBUTING.md",
"chars": 5765,
"preview": "# Contributing to solidtime\n\nContributions are greatly apprecited, please make sure to read the rules and vision for sol"
},
{
"path": "LICENSE.md",
"chars": 34202,
"preview": "GNU Affero General Public License\n=================================\n\n_Version 3, 19 November 2007_\n_Copyright © 2007 Fre"
},
{
"path": "README.md",
"chars": 3185,
"preview": "# solidtime - The modern Open-Source Time Tracker\n\n[;\n\nnamespace App\\Actions\\Fortify;\n\nuse App\\Enums\\Weekday;\nuse App\\Events\\NewsletterRegiste"
},
{
"path": "app/Actions/Fortify/PasswordValidationRules.php",
"chars": 437,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Fortify;\n\nuse Illuminate\\Contracts\\Validation\\Rule;\nuse Illuminat"
},
{
"path": "app/Actions/Fortify/ResetUserPassword.php",
"chars": 719,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Fortify;\n\nuse App\\Models\\User;\nuse Illuminate\\Support\\Facades\\Has"
},
{
"path": "app/Actions/Fortify/UpdateUserPassword.php",
"chars": 950,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Fortify;\n\nuse App\\Models\\User;\nuse Illuminate\\Support\\Facades\\Has"
},
{
"path": "app/Actions/Fortify/UpdateUserProfileInformation.php",
"chars": 2394,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Fortify;\n\nuse App\\Enums\\Weekday;\nuse App\\Models\\User;\nuse Illumin"
},
{
"path": "app/Actions/Jetstream/AddOrganizationMember.php",
"chars": 2984,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Jetstream;\n\nuse App\\Enums\\Role;\nuse App\\Models\\Organization;\nuse "
},
{
"path": "app/Actions/Jetstream/CreateOrganization.php",
"chars": 1726,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Jetstream;\n\nuse App\\Events\\AfterCreateOrganization;\nuse App\\Model"
},
{
"path": "app/Actions/Jetstream/DeleteOrganization.php",
"chars": 469,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Jetstream;\n\nuse App\\Models\\Organization;\nuse App\\Service\\Deletion"
},
{
"path": "app/Actions/Jetstream/DeleteUser.php",
"chars": 706,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Jetstream;\n\nuse App\\Exceptions\\Api\\ApiException;\nuse App\\Models\\U"
},
{
"path": "app/Actions/Jetstream/InviteOrganizationMember.php",
"chars": 550,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Jetstream;\n\nuse App\\Exceptions\\MovedToApiException;\nuse App\\Model"
},
{
"path": "app/Actions/Jetstream/RemoveOrganizationMember.php",
"chars": 531,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Jetstream;\n\nuse App\\Exceptions\\MovedToApiException;\nuse App\\Model"
},
{
"path": "app/Actions/Jetstream/UpdateMemberRole.php",
"chars": 501,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Jetstream;\n\nuse App\\Enums\\Role;\nuse App\\Exceptions\\MovedToApiExce"
},
{
"path": "app/Actions/Jetstream/UpdateOrganization.php",
"chars": 1266,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Jetstream;\n\nuse App\\Models\\Organization;\nuse App\\Models\\User;\nuse"
},
{
"path": "app/Actions/Jetstream/ValidateOrganizationDeletion.php",
"chars": 734,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Jetstream;\n\nuse App\\Models\\Organization;\nuse App\\Models\\User;\nuse"
},
{
"path": "app/Console/Commands/Admin/OrganizationDeleteCommand.php",
"chars": 1501,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Console\\Commands\\Admin;\n\nuse App\\Models\\Organization;\nuse App\\Service\\Del"
},
{
"path": "app/Console/Commands/Admin/UserCreateCommand.php",
"chars": 2773,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Console\\Commands\\Admin;\n\nuse App\\Enums\\Weekday;\nuse App\\Models\\Organizati"
},
{
"path": "app/Console/Commands/Admin/UserVerifyCommand.php",
"chars": 1424,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Console\\Commands\\Admin;\n\nuse App\\Models\\User;\nuse Illuminate\\Auth\\Events\\"
},
{
"path": "app/Console/Commands/Auth/AuthSendReminderForExpiringApiTokensCommand.php",
"chars": 4117,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Console\\Commands\\Auth;\n\nuse App\\Mail\\AuthApiTokenExpirationReminderMail;\n"
},
{
"path": "app/Console/Commands/Correction/CorrectionPlaceholderMembersCommand.php",
"chars": 1755,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Console\\Commands\\Correction;\n\nuse App\\Enums\\Role;\nuse App\\Models\\Member;\n"
},
{
"path": "app/Console/Commands/Report/ReportSetExpiredToPrivateCommand.php",
"chars": 2280,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Console\\Commands\\Report;\n\nuse App\\Models\\Report;\nuse Illuminate\\Console\\C"
},
{
"path": "app/Console/Commands/SelfHost/SelfHostCheckForUpdateCommand.php",
"chars": 1071,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Console\\Commands\\SelfHost;\n\nuse App\\Service\\ApiService;\nuse Illuminate\\Co"
},
{
"path": "app/Console/Commands/SelfHost/SelfHostDatabaseConsistency.php",
"chars": 4641,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Console\\Commands\\SelfHost;\n\nuse Illuminate\\Console\\Command;\nuse Illuminat"
},
{
"path": "app/Console/Commands/SelfHost/SelfHostGenerateKeysCommand.php",
"chars": 2192,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Console\\Commands\\SelfHost;\n\nuse Illuminate\\Console\\Command;\nuse Illuminat"
},
{
"path": "app/Console/Commands/SelfHost/SelfHostTelemetryCommand.php",
"chars": 841,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Console\\Commands\\SelfHost;\n\nuse App\\Service\\ApiService;\nuse Illuminate\\Co"
},
{
"path": "app/Console/Commands/Test/TestEmailCommand.php",
"chars": 936,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Console\\Commands\\Test;\n\nuse Illuminate\\Console\\Command;\nuse Illuminate\\Ma"
},
{
"path": "app/Console/Commands/Test/TestJobCommand.php",
"chars": 766,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Console\\Commands\\Test;\n\nuse App\\Jobs\\Test\\TestJob;\nuse App\\Models\\User;\nu"
},
{
"path": "app/Console/Commands/Test/TestOutputCommand.php",
"chars": 663,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Console\\Commands\\Test;\n\nuse Illuminate\\Console\\Command;\n\nclass TestOutput"
},
{
"path": "app/Console/Commands/TimeEntry/TimeEntrySendStillRunningMailsCommand.php",
"chars": 2664,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Console\\Commands\\TimeEntry;\n\nuse App\\Mail\\TimeEntryStillRunningMail;\nuse "
},
{
"path": "app/Console/Kernel.php",
"chars": 2185,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Console;\n\nuse Illuminate\\Console\\Scheduling\\Schedule;\nuse Illuminate\\Foun"
},
{
"path": "app/Enums/CurrencyFormat.php",
"chars": 814,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Enums;\n\nuse Datomatic\\LaravelEnumHelper\\LaravelEnumHelper;\n\nenum Currency"
},
{
"path": "app/Enums/DateFormat.php",
"chars": 1334,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Enums;\n\nuse Datomatic\\LaravelEnumHelper\\LaravelEnumHelper;\n\nenum DateForm"
},
{
"path": "app/Enums/ExportFormat.php",
"chars": 694,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Enums;\n\nuse Maatwebsite\\Excel\\Excel;\n\nenum ExportFormat: string\n{\n cas"
},
{
"path": "app/Enums/IntervalFormat.php",
"chars": 714,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Enums;\n\nuse Datomatic\\LaravelEnumHelper\\LaravelEnumHelper;\n\nenum Interval"
},
{
"path": "app/Enums/NumberFormat.php",
"chars": 823,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Enums;\n\nuse Datomatic\\LaravelEnumHelper\\LaravelEnumHelper;\n\n/**\n * @info "
},
{
"path": "app/Enums/Role.php",
"chars": 229,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Enums;\n\nenum Role: string\n{\n case Owner = 'owner';\n case Admin = 'a"
},
{
"path": "app/Enums/TimeEntryAggregationType.php",
"chars": 1527,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Enums;\n\nuse Datomatic\\LaravelEnumHelper\\LaravelEnumHelper;\n\nenum TimeEntr"
},
{
"path": "app/Enums/TimeEntryAggregationTypeInterval.php",
"chars": 201,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Enums;\n\nenum TimeEntryAggregationTypeInterval: string\n{\n case Day = 'd"
},
{
"path": "app/Enums/TimeEntryRoundingType.php",
"chars": 248,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Enums;\n\nuse Datomatic\\LaravelEnumHelper\\LaravelEnumHelper;\n\nenum TimeEntr"
},
{
"path": "app/Enums/TimeFormat.php",
"chars": 550,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Enums;\n\nuse Datomatic\\LaravelEnumHelper\\LaravelEnumHelper;\n\nenum TimeForm"
},
{
"path": "app/Enums/Weekday.php",
"chars": 2025,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Enums;\n\nuse Datomatic\\LaravelEnumHelper\\LaravelEnumHelper;\nuse Illuminate"
},
{
"path": "app/Events/AfterCreateOrganization.php",
"chars": 570,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Events;\n\nuse App\\Models\\Organization;\nuse Illuminate\\Foundation\\Events\\Di"
},
{
"path": "app/Events/BeforeOrganizationDeletion.php",
"chars": 350,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Events;\n\nuse App\\Models\\Organization;\nuse Illuminate\\Foundation\\Events\\Di"
},
{
"path": "app/Events/DatabaseSeederAfterSeed.php",
"chars": 198,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Events;\n\nuse Illuminate\\Foundation\\Events\\Dispatchable;\n\nclass DatabaseSe"
},
{
"path": "app/Events/DatabaseSeederBeforeDelete.php",
"chars": 201,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Events;\n\nuse Illuminate\\Foundation\\Events\\Dispatchable;\n\nclass DatabaseSe"
},
{
"path": "app/Events/MemberMadeToPlaceholder.php",
"chars": 447,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Events;\n\nuse App\\Models\\Member;\nuse App\\Models\\Organization;\nuse Illumina"
},
{
"path": "app/Events/MemberRemoved.php",
"chars": 437,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Events;\n\nuse App\\Models\\Member;\nuse App\\Models\\Organization;\nuse Illumina"
},
{
"path": "app/Events/NewsletterRegistered.php",
"chars": 457,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Events;\n\nuse Illuminate\\Foundation\\Events\\Dispatchable;\n\nclass Newsletter"
},
{
"path": "app/Exceptions/Api/ApiException.php",
"chars": 1409,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exceptions\\Api;\n\nuse Exception;\nuse Illuminate\\Http\\JsonResponse;\nuse Ill"
},
{
"path": "app/Exceptions/Api/CanNotDeleteUserWhoIsOwnerOfOrganizationWithMultipleMembers.php",
"chars": 259,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exceptions\\Api;\n\nclass CanNotDeleteUserWhoIsOwnerOfOrganizationWithMultip"
},
{
"path": "app/Exceptions/Api/CanNotRemoveOwnerFromOrganization.php",
"chars": 201,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exceptions\\Api;\n\nclass CanNotRemoveOwnerFromOrganization extends ApiExcep"
},
{
"path": "app/Exceptions/Api/ChangingRoleOfPlaceholderIsNotAllowed.php",
"chars": 210,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exceptions\\Api;\n\nclass ChangingRoleOfPlaceholderIsNotAllowed extends ApiE"
},
{
"path": "app/Exceptions/Api/ChangingRoleToPlaceholderIsNotAllowed.php",
"chars": 210,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exceptions\\Api;\n\nclass ChangingRoleToPlaceholderIsNotAllowed extends ApiE"
},
{
"path": "app/Exceptions/Api/EntityStillInUseApiException.php",
"chars": 824,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exceptions\\Api;\n\nclass EntityStillInUseApiException extends ApiException\n"
},
{
"path": "app/Exceptions/Api/FeatureIsNotAvailableInFreePlanApiException.php",
"chars": 210,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exceptions\\Api;\n\nclass FeatureIsNotAvailableInFreePlanApiException extend"
},
{
"path": "app/Exceptions/Api/InactiveUserCanNotBeUsedApiException.php",
"chars": 195,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exceptions\\Api;\n\nclass InactiveUserCanNotBeUsedApiException extends ApiEx"
},
{
"path": "app/Exceptions/Api/InvitationForTheEmailAlreadyExistsApiException.php",
"chars": 215,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exceptions\\Api;\n\nclass InvitationForTheEmailAlreadyExistsApiException ext"
},
{
"path": "app/Exceptions/Api/OnlyOwnerCanChangeOwnership.php",
"chars": 188,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exceptions\\Api;\n\nclass OnlyOwnerCanChangeOwnership extends ApiException\n{"
},
{
"path": "app/Exceptions/Api/OnlyPlaceholdersCanBeMergedIntoAnotherMember.php",
"chars": 225,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exceptions\\Api;\n\nclass OnlyPlaceholdersCanBeMergedIntoAnotherMember exten"
},
{
"path": "app/Exceptions/Api/OrganizationHasNoSubscriptionButMultipleMembersException.php",
"chars": 239,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exceptions\\Api;\n\nclass OrganizationHasNoSubscriptionButMultipleMembersExc"
},
{
"path": "app/Exceptions/Api/OrganizationNeedsAtLeastOneOwner.php",
"chars": 199,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exceptions\\Api;\n\nclass OrganizationNeedsAtLeastOneOwner extends ApiExcept"
},
{
"path": "app/Exceptions/Api/OverlappingTimeEntryApiException.php",
"chars": 184,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exceptions\\Api;\n\nclass OverlappingTimeEntryApiException extends ApiExcept"
},
{
"path": "app/Exceptions/Api/PdfRendererIsNotConfiguredException.php",
"chars": 195,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exceptions\\Api;\n\nclass PdfRendererIsNotConfiguredException extends ApiExc"
},
{
"path": "app/Exceptions/Api/PersonalAccessClientIsNotConfiguredException.php",
"chars": 214,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exceptions\\Api;\n\nclass PersonalAccessClientIsNotConfiguredException exten"
},
{
"path": "app/Exceptions/Api/ThisPlaceholderCanNotBeInvitedUseTheMergeToolInsteadException.php",
"chars": 267,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exceptions\\Api;\n\nclass ThisPlaceholderCanNotBeInvitedUseTheMergeToolInste"
},
{
"path": "app/Exceptions/Api/TimeEntryCanNotBeRestartedApiException.php",
"chars": 199,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exceptions\\Api;\n\nclass TimeEntryCanNotBeRestartedApiException extends Api"
},
{
"path": "app/Exceptions/Api/TimeEntryStillRunningApiException.php",
"chars": 187,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exceptions\\Api;\n\nclass TimeEntryStillRunningApiException extends ApiExcep"
},
{
"path": "app/Exceptions/Api/UserIsAlreadyMemberOfOrganizationApiException.php",
"chars": 213,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exceptions\\Api;\n\nclass UserIsAlreadyMemberOfOrganizationApiException exte"
},
{
"path": "app/Exceptions/Api/UserIsAlreadyMemberOfProjectApiException.php",
"chars": 203,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exceptions\\Api;\n\nclass UserIsAlreadyMemberOfProjectApiException extends A"
},
{
"path": "app/Exceptions/Api/UserNotPlaceholderApiException.php",
"chars": 180,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exceptions\\Api;\n\nclass UserNotPlaceholderApiException extends ApiExceptio"
},
{
"path": "app/Exceptions/Handler.php",
"chars": 1103,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exceptions;\n\nuse Illuminate\\Foundation\\Exceptions\\Handler as ExceptionHan"
},
{
"path": "app/Exceptions/MovedToApiException.php",
"chars": 267,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Exceptions;\n\nuse Symfony\\Component\\HttpKernel\\Exception\\HttpException;\n\nc"
},
{
"path": "app/Extensions/Auditing/Resolvers/CustomIpAddressResolver.php",
"chars": 808,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Extensions\\Auditing\\Resolvers;\n\nuse Illuminate\\Support\\Facades\\Request;\nu"
},
{
"path": "app/Extensions/Fortify/CustomLoginResponse.php",
"chars": 676,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Extensions\\Fortify;\n\nuse Illuminate\\Http\\Request;\nuse Inertia\\Inertia;\nus"
},
{
"path": "app/Extensions/Fortify/CustomTwoFactorLoginResponse.php",
"chars": 761,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Extensions\\Fortify;\n\nuse Illuminate\\Http\\JsonResponse;\nuse Illuminate\\Htt"
},
{
"path": "app/Extensions/Scramble/ApiExceptionTypeToSchema.php",
"chars": 1802,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Extensions\\Scramble;\n\nuse App\\Exceptions\\Api\\ApiException;\nuse Dedoc\\Scra"
},
{
"path": "app/Extensions/Scramble/PaginatedResourceCollectionTypeToSchema.php",
"chars": 4792,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Extensions\\Scramble;\n\nuse App\\Http\\Resources\\PaginatedResourceCollection;"
},
{
"path": "app/Filament/Resources/AuditResource/Pages/CreateAudit.php",
"chars": 279,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\AuditResource\\Pages;\n\nuse App\\Filament\\Resources\\Audit"
},
{
"path": "app/Filament/Resources/AuditResource/Pages/ListAudits.php",
"chars": 357,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\AuditResource\\Pages;\n\nuse App\\Filament\\Resources\\Audit"
},
{
"path": "app/Filament/Resources/AuditResource/Pages/ViewAudit.php",
"chars": 273,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\AuditResource\\Pages;\n\nuse App\\Filament\\Resources\\Audit"
},
{
"path": "app/Filament/Resources/AuditResource.php",
"chars": 3097,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources;\n\nuse App\\Filament\\Resources\\AuditResource\\Pages;\nuse "
},
{
"path": "app/Filament/Resources/ClientResource/Pages/CreateClient.php",
"chars": 283,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\ClientResource\\Pages;\n\nuse App\\Filament\\Resources\\Clie"
},
{
"path": "app/Filament/Resources/ClientResource/Pages/EditClient.php",
"chars": 474,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\ClientResource\\Pages;\n\nuse App\\Filament\\Resources\\Clie"
},
{
"path": "app/Filament/Resources/ClientResource/Pages/ListClients.php",
"chars": 476,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\ClientResource\\Pages;\n\nuse App\\Filament\\Resources\\Clie"
},
{
"path": "app/Filament/Resources/ClientResource.php",
"chars": 2956,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources;\n\nuse App\\Filament\\Resources\\ClientResource\\Pages;\nuse"
},
{
"path": "app/Filament/Resources/FailedJobResource/Pages/ListFailedJobs.php",
"chars": 1483,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\FailedJobResource\\Pages;\n\nuse App\\Filament\\Resources\\F"
},
{
"path": "app/Filament/Resources/FailedJobResource/Pages/ViewFailedJobs.php",
"chars": 290,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\FailedJobResource\\Pages;\n\nuse App\\Filament\\Resources\\F"
},
{
"path": "app/Filament/Resources/FailedJobResource.php",
"chars": 4725,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources;\n\nuse App\\Filament\\Resources\\FailedJobResource\\Pages\\L"
},
{
"path": "app/Filament/Resources/OrganizationInvitationResource/Pages/EditOrganizationInvitation.php",
"chars": 538,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\OrganizationInvitationResource\\Pages;\n\nuse App\\Filamen"
},
{
"path": "app/Filament/Resources/OrganizationInvitationResource/Pages/ListOrganizationInvitations.php",
"chars": 434,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\OrganizationInvitationResource\\Pages;\n\nuse App\\Filamen"
},
{
"path": "app/Filament/Resources/OrganizationInvitationResource/Pages/ViewOrganizationInvitation.php",
"chars": 546,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\OrganizationInvitationResource\\Pages;\n\nuse App\\Filamen"
},
{
"path": "app/Filament/Resources/OrganizationInvitationResource.php",
"chars": 3885,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources;\n\nuse App\\Enums\\Role;\nuse App\\Filament\\Resources\\Organ"
},
{
"path": "app/Filament/Resources/OrganizationResource/Actions/DeleteOrganization.php",
"chars": 1303,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\OrganizationResource\\Actions;\n\nuse App\\Exceptions\\Api\\"
},
{
"path": "app/Filament/Resources/OrganizationResource/Pages/CreateOrganization.php",
"chars": 816,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\OrganizationResource\\Pages;\n\nuse App\\Enums\\Role;\nuse A"
},
{
"path": "app/Filament/Resources/OrganizationResource/Pages/EditOrganization.php",
"chars": 460,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\OrganizationResource\\Pages;\n\nuse App\\Filament\\Resource"
},
{
"path": "app/Filament/Resources/OrganizationResource/Pages/ListOrganizations.php",
"chars": 500,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\OrganizationResource\\Pages;\n\nuse App\\Filament\\Resource"
},
{
"path": "app/Filament/Resources/OrganizationResource/Pages/ViewOrganization.php",
"chars": 506,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\OrganizationResource\\Pages;\n\nuse App\\Filament\\Resource"
},
{
"path": "app/Filament/Resources/OrganizationResource/RelationManagers/InvitationsRelationManager.php",
"chars": 2985,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\OrganizationResource\\RelationManagers;\n\nuse App\\Enums\\"
},
{
"path": "app/Filament/Resources/OrganizationResource/RelationManagers/UsersRelationManager.php",
"chars": 5801,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\OrganizationResource\\RelationManagers;\n\nuse App\\Enums\\"
},
{
"path": "app/Filament/Resources/OrganizationResource.php",
"chars": 10901,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources;\n\nuse App\\Enums\\CurrencyFormat;\nuse App\\Enums\\DateForm"
},
{
"path": "app/Filament/Resources/ProjectMemberResource/Pages/CreateProjectMember.php",
"chars": 311,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\ProjectMemberResource\\Pages;\n\nuse App\\Filament\\Resourc"
},
{
"path": "app/Filament/Resources/ProjectMemberResource/Pages/EditProjectMember.php",
"chars": 502,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\ProjectMemberResource\\Pages;\n\nuse App\\Filament\\Resourc"
},
{
"path": "app/Filament/Resources/ProjectMemberResource/Pages/ListProjectMembers.php",
"chars": 504,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\ProjectMemberResource\\Pages;\n\nuse App\\Filament\\Resourc"
},
{
"path": "app/Filament/Resources/ProjectMemberResource/Pages/ViewProjectMembers.php",
"chars": 511,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\ProjectMemberResource\\Pages;\n\nuse App\\Filament\\Resourc"
},
{
"path": "app/Filament/Resources/ProjectMemberResource.php",
"chars": 2834,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources;\n\nuse App\\Filament\\Resources\\ProjectMemberResource\\Pag"
},
{
"path": "app/Filament/Resources/ProjectResource/Pages/CreateProject.php",
"chars": 287,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\ProjectResource\\Pages;\n\nuse App\\Filament\\Resources\\Pro"
},
{
"path": "app/Filament/Resources/ProjectResource/Pages/EditProject.php",
"chars": 478,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\ProjectResource\\Pages;\n\nuse App\\Filament\\Resources\\Pro"
},
{
"path": "app/Filament/Resources/ProjectResource/Pages/ListProjects.php",
"chars": 480,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\ProjectResource\\Pages;\n\nuse App\\Filament\\Resources\\Pro"
},
{
"path": "app/Filament/Resources/ProjectResource/RelationManagers/ProjectMembersRelationManager.php",
"chars": 1795,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\ProjectResource\\RelationManagers;\n\nuse App\\Filament\\Re"
},
{
"path": "app/Filament/Resources/ProjectResource.php",
"chars": 3499,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources;\n\nuse App\\Filament\\Resources\\ProjectResource\\Pages;\nus"
},
{
"path": "app/Filament/Resources/ReportResource/Pages/EditReport.php",
"chars": 474,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\ReportResource\\Pages;\n\nuse App\\Filament\\Resources\\Repo"
},
{
"path": "app/Filament/Resources/ReportResource/Pages/ListReports.php",
"chars": 370,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\ReportResource\\Pages;\n\nuse App\\Filament\\Resources\\Repo"
},
{
"path": "app/Filament/Resources/ReportResource/Pages/ViewReport.php",
"chars": 482,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\ReportResource\\Pages;\n\nuse App\\Filament\\Resources\\Repo"
},
{
"path": "app/Filament/Resources/ReportResource.php",
"chars": 5106,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources;\n\nuse App\\Filament\\Resources\\ReportResource\\Pages;\nuse"
},
{
"path": "app/Filament/Resources/TagResource/Pages/CreateTag.php",
"chars": 271,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\TagResource\\Pages;\n\nuse App\\Filament\\Resources\\TagReso"
},
{
"path": "app/Filament/Resources/TagResource/Pages/EditTag.php",
"chars": 462,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\TagResource\\Pages;\n\nuse App\\Filament\\Resources\\TagReso"
},
{
"path": "app/Filament/Resources/TagResource/Pages/ListTags.php",
"chars": 464,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\TagResource\\Pages;\n\nuse App\\Filament\\Resources\\TagReso"
},
{
"path": "app/Filament/Resources/TagResource.php",
"chars": 2928,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources;\n\nuse App\\Filament\\Resources\\TagResource\\Pages;\nuse Ap"
},
{
"path": "app/Filament/Resources/TaskResource/Pages/CreateTask.php",
"chars": 275,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\TaskResource\\Pages;\n\nuse App\\Filament\\Resources\\TaskRe"
},
{
"path": "app/Filament/Resources/TaskResource/Pages/EditTask.php",
"chars": 466,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\TaskResource\\Pages;\n\nuse App\\Filament\\Resources\\TaskRe"
},
{
"path": "app/Filament/Resources/TaskResource/Pages/ListTasks.php",
"chars": 468,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\TaskResource\\Pages;\n\nuse App\\Filament\\Resources\\TaskRe"
},
{
"path": "app/Filament/Resources/TaskResource.php",
"chars": 3063,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources;\n\nuse App\\Filament\\Resources\\TaskResource\\Pages;\nuse A"
},
{
"path": "app/Filament/Resources/TimeEntryResource/Pages/CreateTimeEntry.php",
"chars": 851,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\TimeEntryResource\\Pages;\n\nuse App\\Filament\\Resources\\T"
},
{
"path": "app/Filament/Resources/TimeEntryResource/Pages/EditTimeEntry.php",
"chars": 1040,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\TimeEntryResource\\Pages;\n\nuse App\\Filament\\Resources\\T"
},
{
"path": "app/Filament/Resources/TimeEntryResource/Pages/ListTimeEntries.php",
"chars": 489,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\TimeEntryResource\\Pages;\n\nuse App\\Filament\\Resources\\T"
},
{
"path": "app/Filament/Resources/TimeEntryResource.php",
"chars": 4973,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources;\n\nuse App\\Filament\\Resources\\TimeEntryResource\\Pages;\n"
},
{
"path": "app/Filament/Resources/TokenResource/Pages/ListTokens.php",
"chars": 366,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\TokenResource\\Pages;\n\nuse App\\Filament\\Resources\\Token"
},
{
"path": "app/Filament/Resources/TokenResource/Pages/ViewToken.php",
"chars": 363,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\TokenResource\\Pages;\n\nuse App\\Filament\\Resources\\Token"
},
{
"path": "app/Filament/Resources/TokenResource.php",
"chars": 5096,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources;\n\nuse App\\Filament\\Resources\\TokenResource\\Pages;\nuse "
},
{
"path": "app/Filament/Resources/UserResource/Actions/DeleteUser.php",
"chars": 1263,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\UserResource\\Actions;\n\nuse App\\Exceptions\\Api\\ApiExcep"
},
{
"path": "app/Filament/Resources/UserResource/Pages/CreateUser.php",
"chars": 810,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\UserResource\\Pages;\n\nuse App\\Enums\\Weekday;\nuse App\\Fi"
},
{
"path": "app/Filament/Resources/UserResource/Pages/EditUser.php",
"chars": 528,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\UserResource\\Pages;\n\nuse App\\Filament\\Resources\\UserRe"
},
{
"path": "app/Filament/Resources/UserResource/Pages/ListUsers.php",
"chars": 468,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\UserResource\\Pages;\n\nuse App\\Filament\\Resources\\UserRe"
},
{
"path": "app/Filament/Resources/UserResource/Pages/ViewUser.php",
"chars": 590,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\UserResource\\Pages;\n\nuse App\\Filament\\Resources\\UserRe"
},
{
"path": "app/Filament/Resources/UserResource/RelationManagers/OrganizationsRelationManager.php",
"chars": 3825,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\UserResource\\RelationManagers;\n\nuse App\\Enums\\Role;\nus"
},
{
"path": "app/Filament/Resources/UserResource/RelationManagers/OwnedOrganizationsRelationManager.php",
"chars": 1661,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\UserResource\\RelationManagers;\n\nuse App\\Filament\\Resou"
},
{
"path": "app/Filament/Resources/UserResource.php",
"chars": 9992,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources;\n\nuse App\\Enums\\Weekday;\nuse App\\Exceptions\\Api\\ApiExc"
},
{
"path": "app/Filament/Widgets/ActiveUserOverview.php",
"chars": 1485,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Widgets;\n\nuse App\\Models\\TimeEntry;\nuse App\\Models\\User;\nuse Fil"
},
{
"path": "app/Filament/Widgets/ServerOverview.php",
"chars": 1028,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Widgets;\n\nuse Filament\\Widgets\\Widget;\nuse Illuminate\\Support\\Fa"
},
{
"path": "app/Filament/Widgets/TimeEntriesCreated.php",
"chars": 1873,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Widgets;\n\nuse App\\Models\\TimeEntry;\nuse Filament\\Widgets\\ChartWi"
},
{
"path": "app/Filament/Widgets/TimeEntriesImported.php",
"chars": 1874,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Widgets;\n\nuse App\\Models\\TimeEntry;\nuse Filament\\Widgets\\ChartWi"
},
{
"path": "app/Filament/Widgets/UserRegistrations.php",
"chars": 1880,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Widgets;\n\nuse App\\Models\\User;\nuse Filament\\Widgets\\ChartWidget;"
},
{
"path": "app/Http/Controllers/Api/V1/ApiTokenController.php",
"chars": 3768,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Api\\V1;\n\nuse App\\Exceptions\\Api\\PersonalAccessClientIsNo"
},
{
"path": "app/Http/Controllers/Api/V1/ChartController.php",
"chars": 6091,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Api\\V1;\n\nuse App\\Enums\\Role;\nuse App\\Models\\Organization"
},
{
"path": "app/Http/Controllers/Api/V1/ClientController.php",
"chars": 3707,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Api\\V1;\n\nuse App\\Exceptions\\Api\\EntityStillInUseApiExcep"
},
{
"path": "app/Http/Controllers/Api/V1/Controller.php",
"chars": 1494,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Api\\V1;\n\nuse App\\Models\\Organization;\nuse App\\Service\\Bi"
},
{
"path": "app/Http/Controllers/Api/V1/CurrencyController.php",
"chars": 999,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Api\\V1;\n\nuse App\\Http\\Controllers\\Controller;\nuse App\\Se"
},
{
"path": "app/Http/Controllers/Api/V1/ExportController.php",
"chars": 1052,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Api\\V1;\n\nuse App\\Models\\Organization;\nuse App\\Service\\Ex"
},
{
"path": "app/Http/Controllers/Api/V1/ImportController.php",
"chars": 3357,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Api\\V1;\n\nuse App\\Http\\Requests\\V1\\Import\\ImportRequest;\n"
},
{
"path": "app/Http/Controllers/Api/V1/InvitationController.php",
"chars": 3417,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Api\\V1;\n\nuse App\\Exceptions\\Api\\InvitationForTheEmailAlr"
},
{
"path": "app/Http/Controllers/Api/V1/MemberController.php",
"chars": 7499,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Api\\V1;\n\nuse App\\Enums\\Role;\nuse App\\Events\\MemberMadeTo"
},
{
"path": "app/Http/Controllers/Api/V1/OrganizationController.php",
"chars": 3103,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Api\\V1;\n\nuse App\\Enums\\Role;\nuse App\\Http\\Requests\\V1\\Or"
},
{
"path": "app/Http/Controllers/Api/V1/ProjectController.php",
"chars": 6796,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Api\\V1;\n\nuse App\\Enums\\Role;\nuse App\\Exceptions\\Api\\Enti"
},
{
"path": "app/Http/Controllers/Api/V1/ProjectMemberController.php",
"chars": 5360,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Api\\V1;\n\nuse App\\Exceptions\\Api\\InactiveUserCanNotBeUsed"
},
{
"path": "app/Http/Controllers/Api/V1/Public/ReportController.php",
"chars": 3750,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Api\\V1\\Public;\n\nuse App\\Enums\\TimeEntryAggregationType;\n"
},
{
"path": "app/Http/Controllers/Api/V1/ReportController.php",
"chars": 6599,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Api\\V1;\n\nuse App\\Enums\\Weekday;\nuse App\\Http\\Requests\\V1"
},
{
"path": "app/Http/Controllers/Api/V1/TagController.php",
"chars": 2937,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Api\\V1;\n\nuse App\\Exceptions\\Api\\EntityStillInUseApiExcep"
},
{
"path": "app/Http/Controllers/Api/V1/TaskController.php",
"chars": 5944,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Api\\V1;\n\nuse App\\Exceptions\\Api\\EntityStillInUseApiExcep"
},
{
"path": "app/Http/Controllers/Api/V1/TimeEntryController.php",
"chars": 36982,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Api\\V1;\n\nuse App\\Enums\\ExportFormat;\nuse App\\Enums\\Role;"
},
{
"path": "app/Http/Controllers/Api/V1/UserController.php",
"chars": 519,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Api\\V1;\n\nuse App\\Http\\Resources\\V1\\User\\UserResource;\nus"
},
{
"path": "app/Http/Controllers/Api/V1/UserMembershipController.php",
"chars": 868,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Api\\V1;\n\nuse App\\Http\\Resources\\V1\\Member\\PersonalMember"
},
{
"path": "app/Http/Controllers/Api/V1/UserTimeEntryController.php",
"chars": 1312,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Api\\V1;\n\nuse App\\Http\\Resources\\V1\\TimeEntry\\TimeEntryRe"
},
{
"path": "app/Http/Controllers/Controller.php",
"chars": 1939,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers;\n\nuse App\\Models\\Member;\nuse App\\Models\\Organization;\nus"
},
{
"path": "app/Http/Controllers/Web/Controller.php",
"chars": 140,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Web;\n\nabstract class Controller extends \\App\\Http\\Contro"
},
{
"path": "app/Http/Controllers/Web/DashboardController.php",
"chars": 962,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Web;\n\nuse App\\Enums\\Role;\nuse App\\Service\\DashboardServi"
},
{
"path": "app/Http/Controllers/Web/HealthCheckController.php",
"chars": 2513,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Web;\n\nuse App\\Http\\Controllers\\Controller;\nuse App\\Model"
},
{
"path": "app/Http/Controllers/Web/HomeController.php",
"chars": 393,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Web;\n\nuse Illuminate\\Http\\RedirectResponse;\nuse Illumina"
},
{
"path": "app/Http/Kernel.php",
"chars": 3224,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http;\n\nuse App\\Http\\Middleware\\CheckOrganizationBlocked;\nuse App\\Http\\Mid"
},
{
"path": "app/Http/Middleware/Authenticate.php",
"chars": 435,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Auth\\Middleware\\Authenticate as Middlewa"
},
{
"path": "app/Http/Middleware/CheckOrganizationBlocked.php",
"chars": 1094,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Middleware;\n\nuse App\\Exceptions\\Api\\OrganizationHasNoSubscriptionBut"
},
{
"path": "app/Http/Middleware/EncryptCookies.php",
"chars": 333,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Middleware;\n\nuse Illuminate\\Cookie\\Middleware\\EncryptCookies as Midd"
},
{
"path": "app/Http/Middleware/EnsureEmailIsVerified.php",
"chars": 839,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Middleware;\n\nuse Closure;\nuse Illuminate\\Http\\Request;\nuse Illuminat"
}
]
// ... and 1008 more files (download for full content)
About this extraction
This page contains the full source code of the solidtime-io/solidtime GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 1208 files (3.9 MB), approximately 1.1M tokens, and a symbol index with 2769 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.