mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-08-08 16:22:16 +01:00
Compare commits
55 Commits
feature/us
...
feature/cl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
819dfd5037 | ||
|
|
c94aa8038d | ||
|
|
c9e84260b1 | ||
|
|
9a53f903d8 | ||
|
|
d50ce52b5b | ||
|
|
aea310e639 | ||
|
|
a94627321b | ||
|
|
806d138fc9 | ||
|
|
240dd809f4 | ||
|
|
dedb50ea73 | ||
|
|
6fe856fd31 | ||
|
|
20735c2fed | ||
|
|
b14e40c64b | ||
|
|
f2277ff708 | ||
|
|
6a197f7f34 | ||
|
|
24c94af952 | ||
|
|
111ce94150 | ||
|
|
49e69b85a6 | ||
|
|
90a5c2b87c | ||
|
|
6b01034bdd | ||
|
|
a4c400ef4e | ||
|
|
5d01b20dbf | ||
|
|
24875f9424 | ||
|
|
4975cf1dab | ||
|
|
b3fb04c4be | ||
|
|
0cc8d762a5 | ||
|
|
e3e45161a1 | ||
|
|
0c825a691e | ||
|
|
24775d2c47 | ||
|
|
c5c129b239 | ||
|
|
89a9341d91 | ||
|
|
bffd0773be | ||
|
|
56ea0ed90e | ||
|
|
24c19e7e7c | ||
|
|
734aab6353 | ||
|
|
5eb1a6a006 | ||
|
|
d0334bd730 | ||
|
|
fe4e903203 | ||
|
|
43e42ace54 | ||
|
|
84728f0914 | ||
|
|
8f02f98afc | ||
|
|
c1ecd0eff5 | ||
|
|
486b5d2152 | ||
|
|
5476b4e5a9 | ||
|
|
ceec4cbf62 | ||
|
|
372c7b02a0 | ||
|
|
cb8047028c | ||
|
|
e29be581fa | ||
|
|
02da133fb3 | ||
|
|
d00fe2baff | ||
|
|
a73fe59892 | ||
|
|
5d744d70c4 | ||
|
|
12d58ee42c | ||
|
|
f9be92894e | ||
|
|
a30d192ea2 |
24
.github/workflows/build-onpremise.yml
vendored
24
.github/workflows/build-onpremise.yml
vendored
@@ -46,9 +46,9 @@ jobs:
|
||||
- name: "Get Previous tag (normal push)"
|
||||
id: previoustag
|
||||
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
|
||||
uses: "WyriHaximus/github-action-get-previous-tag@v1"
|
||||
uses: "WyriHaximus/github-action-get-previous-tag@v2"
|
||||
with:
|
||||
prefix: "v"
|
||||
pattern: "v*[0-9].*[0-9].*[0-9]"
|
||||
|
||||
- name: "Get version"
|
||||
id: release-version
|
||||
@@ -124,27 +124,27 @@ jobs:
|
||||
|
||||
- name: "Docker meta"
|
||||
id: "meta"
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@v6
|
||||
with:
|
||||
images: |
|
||||
${{ env.DOCKER_REPO }}
|
||||
|
||||
- name: "Login to solidtime OnPremise Registry"
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
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
|
||||
uses: docker/setup-qemu-action@v4
|
||||
|
||||
- name: "Set up Docker Buildx"
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: "Build and push by digest"
|
||||
id: build
|
||||
uses: docker/build-push-action@v6
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
file: docker/prod/Dockerfile
|
||||
@@ -163,7 +163,7 @@ jobs:
|
||||
touch "${{ runner.temp }}/digests/${digest#sha256:}"
|
||||
|
||||
- name: "Upload digest"
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: digests-${{ env.PLATFORM_PAIR }}
|
||||
path: ${{ runner.temp }}/digests/*
|
||||
@@ -177,25 +177,25 @@ jobs:
|
||||
- build
|
||||
steps:
|
||||
- name: "Download digests"
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
path: ${{ runner.temp }}/digests
|
||||
pattern: digests-*
|
||||
merge-multiple: true
|
||||
|
||||
- name: "Login to solidtime OnPremise Registry"
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
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
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: "Docker meta"
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@v6
|
||||
with:
|
||||
images: |
|
||||
${{ env.DOCKER_REPO }}
|
||||
|
||||
14
.github/workflows/build-private.yml
vendored
14
.github/workflows/build-private.yml
vendored
@@ -33,9 +33,9 @@ jobs:
|
||||
- name: "Get Previous tag (normal push)"
|
||||
id: previoustag
|
||||
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
|
||||
uses: "WyriHaximus/github-action-get-previous-tag@v1"
|
||||
uses: "WyriHaximus/github-action-get-previous-tag@v2"
|
||||
with:
|
||||
prefix: "v"
|
||||
pattern: "v*[0-9].*[0-9].*[0-9]"
|
||||
|
||||
- name: "Get version"
|
||||
id: version
|
||||
@@ -160,7 +160,7 @@ jobs:
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
|
||||
- name: "Login to GitHub Container Registry"
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: rg.fr-par.scw.cloud/solidtime
|
||||
username: nologin
|
||||
@@ -168,7 +168,7 @@ jobs:
|
||||
|
||||
- name: "Docker meta"
|
||||
id: "meta"
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@v6
|
||||
with:
|
||||
images: rg.fr-par.scw.cloud/solidtime/solidtime
|
||||
tags: |
|
||||
@@ -179,13 +179,13 @@ jobs:
|
||||
type=sha,format=long
|
||||
|
||||
- name: "Set up QEMU"
|
||||
uses: docker/setup-qemu-action@v3
|
||||
uses: docker/setup-qemu-action@v4
|
||||
|
||||
- name: "Set up Docker Buildx"
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: "Build and push"
|
||||
uses: docker/build-push-action@v6
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
build-args: |
|
||||
|
||||
28
.github/workflows/build-public.yml
vendored
28
.github/workflows/build-public.yml
vendored
@@ -47,9 +47,9 @@ jobs:
|
||||
- name: "Get Previous tag (normal push)"
|
||||
id: previoustag
|
||||
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
|
||||
uses: "WyriHaximus/github-action-get-previous-tag@v1"
|
||||
uses: "WyriHaximus/github-action-get-previous-tag@v2"
|
||||
with:
|
||||
prefix: "v"
|
||||
pattern: "v*[0-9].*[0-9].*[0-9]"
|
||||
|
||||
- name: "Get version"
|
||||
id: release-version
|
||||
@@ -109,34 +109,34 @@ jobs:
|
||||
|
||||
- name: "Docker meta"
|
||||
id: "meta"
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@v6
|
||||
with:
|
||||
images: |
|
||||
${{ env.DOCKERHUB_REPO }}
|
||||
${{ env.GHCR_REPO }}
|
||||
|
||||
- name: "Login to Docker Hub Container Registry"
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: "Login to GitHub Container Registry"
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: "Set up QEMU"
|
||||
uses: docker/setup-qemu-action@v3
|
||||
uses: docker/setup-qemu-action@v4
|
||||
|
||||
- name: "Set up Docker Buildx"
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: "Build and push by digest"
|
||||
id: build
|
||||
uses: docker/build-push-action@v6
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
file: docker/prod/Dockerfile
|
||||
@@ -155,7 +155,7 @@ jobs:
|
||||
touch "${{ runner.temp }}/digests/${digest#sha256:}"
|
||||
|
||||
- name: "Upload digest"
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: digests-${{ env.PLATFORM_PAIR }}
|
||||
path: ${{ runner.temp }}/digests/*
|
||||
@@ -169,31 +169,31 @@ jobs:
|
||||
- build
|
||||
steps:
|
||||
- name: "Download digests"
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
path: ${{ runner.temp }}/digests
|
||||
pattern: digests-*
|
||||
merge-multiple: true
|
||||
|
||||
- name: "Login to Docker Hub"
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: "Login to GHCR"
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: "Set up Docker Buildx"
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: "Docker meta"
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@v6
|
||||
with:
|
||||
images: |
|
||||
${{ env.DOCKERHUB_REPO }}
|
||||
|
||||
2
.github/workflows/generate-api-docs.yml
vendored
2
.github/workflows/generate-api-docs.yml
vendored
@@ -52,7 +52,7 @@ jobs:
|
||||
run: php artisan scramble:export --path=build/api-docs.json
|
||||
|
||||
- name: "Upload API docs to GitHub"
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: api-docs.json
|
||||
path: build/api-docs.json
|
||||
|
||||
4
.github/workflows/npm-test-unit.yml
vendored
4
.github/workflows/npm-test-unit.yml
vendored
@@ -13,10 +13,10 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: "Use Node.js"
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: '20.x'
|
||||
|
||||
|
||||
2
.github/workflows/phpunit.yml
vendored
2
.github/workflows/phpunit.yml
vendored
@@ -68,7 +68,7 @@ jobs:
|
||||
run: php artisan test --stop-on-failure --coverage-text --coverage-clover=coverage.xml
|
||||
|
||||
- name: "Upload coverage reports to Codecov"
|
||||
uses: codecov/codecov-action@v5.5.1
|
||||
uses: codecov/codecov-action@v7.0.0
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
slug: solidtime-io/solidtime
|
||||
|
||||
8
.github/workflows/playwright.yml
vendored
8
.github/workflows/playwright.yml
vendored
@@ -86,7 +86,7 @@ jobs:
|
||||
MAILPIT_BASE_URL: 'http://localhost:8025'
|
||||
|
||||
- name: "Upload blob report"
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
if: always()
|
||||
with:
|
||||
name: blob-report-${{ matrix.shardIndex }}
|
||||
@@ -102,7 +102,7 @@ jobs:
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: "Setup node"
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: '20.x'
|
||||
|
||||
@@ -110,7 +110,7 @@ jobs:
|
||||
run: npm ci
|
||||
|
||||
- name: "Download blob reports"
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
path: all-blob-reports
|
||||
pattern: blob-report-*
|
||||
@@ -120,7 +120,7 @@ jobs:
|
||||
run: npx playwright merge-reports --reporter html ./all-blob-reports
|
||||
|
||||
- name: "Upload merged HTML report"
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: playwright-report
|
||||
path: playwright-report/
|
||||
|
||||
@@ -116,10 +116,12 @@ class ClockifyTimeEntriesImporter extends DefaultImporter
|
||||
throw new ImportException('Time entry description is too long');
|
||||
}
|
||||
$timeEntry->description = $record['Description'];
|
||||
if (! in_array($record['Billable'], ['Yes', 'No'], true)) {
|
||||
throw new ImportException('Invalid billable value');
|
||||
if (isset($record['Billable'])) {
|
||||
if (! in_array($record['Billable'], ['Yes', 'No'], true)) {
|
||||
throw new ImportException('Invalid billable value');
|
||||
}
|
||||
$timeEntry->billable = $record['Billable'] === 'Yes';
|
||||
}
|
||||
$timeEntry->billable = $record['Billable'] === 'Yes';
|
||||
$timeEntry->tags = $this->getTags($record['Tags']);
|
||||
$timeEntry->is_imported = true;
|
||||
|
||||
@@ -219,7 +221,6 @@ class ClockifyTimeEntriesImporter extends DefaultImporter
|
||||
'Group',
|
||||
'Email',
|
||||
'Tags',
|
||||
'Billable',
|
||||
'Start Date',
|
||||
'Start Time',
|
||||
'End Date',
|
||||
|
||||
@@ -43,17 +43,17 @@ onMounted(async () => {
|
||||
<template v-else>
|
||||
<UpdateTeamNameForm :team="team" :permissions="permissions" />
|
||||
|
||||
<SectionBorder />
|
||||
<SectionBorder v-if="permissions.canUpdateTeam" />
|
||||
<OrganizationBillableRate v-if="permissions.canUpdateTeam" :team="team" />
|
||||
<SectionBorder />
|
||||
|
||||
<SectionBorder v-if="permissions.canUpdateTeam" />
|
||||
<OrganizationFormatSettings v-if="permissions.canUpdateTeam" :team="team" />
|
||||
<SectionBorder />
|
||||
|
||||
<SectionBorder v-if="permissions.canUpdateTeam" />
|
||||
<OrganizationTimeEntrySettings v-if="permissions.canUpdateTeam" />
|
||||
<SectionBorder />
|
||||
|
||||
<template v-if="permissions.canDeleteTeam">
|
||||
<SectionBorder />
|
||||
<DeleteTeamForm class="mt-10 sm:mt-0" :team="team" />
|
||||
</template>
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
"Project","Client","Description","Task","User","Group","Email","Tags","Start Date","Start Time","End Date","End Time","Duration (h)","Duration (decimal)","Billable Rate (USD)","Billable Amount (USD)"
|
||||
"Project without Client","","","","Peter Tester","","peter.test@email.test","Development, Backend","03/04/2024","10:23:52 AM","03/04/2024","10:23:52 AM","00:00:00","0.00","0.00","0.00"
|
||||
"Project for Big Company","Big Company","Working hard","Task 1","Peter Tester","","peter.test@email.test","","03/04/2024","10:23 AM","03/04/2024","11:23:01 AM","01:00:01","0.00","0.00","0.00"
|
||||
|
@@ -41,6 +41,30 @@ class ClockifyTimeEntriesImporterTest extends ImporterTestAbstract
|
||||
$this->assertSame(1, $report->clientsCreated);
|
||||
}
|
||||
|
||||
public function test_import_of_test_file_without_billable_works_and_defaults_to_non_billable(): void
|
||||
{
|
||||
// Arrange
|
||||
$organization = Organization::factory()->create();
|
||||
$timezone = 'Europe/Vienna';
|
||||
$importer = new ClockifyTimeEntriesImporter;
|
||||
$importer->init($organization);
|
||||
$data = Storage::disk('testfiles')->get('clockify_time_entries_import_test_4.csv');
|
||||
|
||||
// Act
|
||||
$importer->importData($data, $timezone);
|
||||
$report = $importer->getReport();
|
||||
|
||||
// Assert
|
||||
$testScenario = $this->checkTestScenarioAfterImportExcludingTimeEntries(false, true);
|
||||
$this->checkTimeEntries($testScenario, false, true);
|
||||
$this->assertSame(2, $report->timeEntriesCreated);
|
||||
$this->assertSame(2, $report->tagsCreated);
|
||||
$this->assertSame(1, $report->tasksCreated);
|
||||
$this->assertSame(1, $report->usersCreated);
|
||||
$this->assertSame(2, $report->projectsCreated);
|
||||
$this->assertSame(1, $report->clientsCreated);
|
||||
}
|
||||
|
||||
public function test_import_of_test_with_special_characters_description_succeeds(): void
|
||||
{
|
||||
// Arrange
|
||||
|
||||
@@ -26,7 +26,7 @@ class ImporterTestAbstract extends TestCase
|
||||
/**
|
||||
* @return object{user1: User, project1: Project, project2: Project, tag1: Tag, tag2: Tag}
|
||||
*/
|
||||
protected function checkTestScenarioAfterImportExcludingTimeEntries(bool $detailed = false): object
|
||||
protected function checkTestScenarioAfterImportExcludingTimeEntries(bool $detailed = false, bool $billableDefault = false): object
|
||||
{
|
||||
$users = User::all();
|
||||
$this->assertCount(2, $users);
|
||||
@@ -80,12 +80,12 @@ class ImporterTestAbstract extends TestCase
|
||||
$this->assertSame('#ef5350', $project1->color);
|
||||
$this->assertSame(null, $project1->billable_rate);
|
||||
// Project for Big Company
|
||||
$this->assertSame(true, $project2->is_billable);
|
||||
$this->assertSame(! $billableDefault, $project2->is_billable);
|
||||
$this->assertSame(false, $project2->is_public);
|
||||
$this->assertSame('#ec407a', $project2->color);
|
||||
$this->assertSame(10001, $project2->billable_rate);
|
||||
// Project (Archived)
|
||||
$this->assertSame(true, $project3->is_billable);
|
||||
$this->assertSame(! $billableDefault, $project3->is_billable);
|
||||
$this->assertSame(true, $project3->is_public);
|
||||
$this->assertSame('#6a407f', $project3->color);
|
||||
$this->assertSame(null, $project3->billable_rate);
|
||||
@@ -176,7 +176,7 @@ class ImporterTestAbstract extends TestCase
|
||||
/**
|
||||
* @param object{user1: User, project1: Project, project2: Project, tag1: Tag, tag2: Tag} $testScenario
|
||||
*/
|
||||
protected function checkTimeEntries(object $testScenario, bool $secondRun = false): void
|
||||
protected function checkTimeEntries(object $testScenario, bool $secondRun = false, bool $billableDefault = false): void
|
||||
{
|
||||
$timeEntries = TimeEntry::all();
|
||||
if ($secondRun) {
|
||||
@@ -197,7 +197,7 @@ class ImporterTestAbstract extends TestCase
|
||||
$this->assertSame('Working hard', $timeEntry2->description);
|
||||
$this->assertSame('2024-03-04 09:23:00', $timeEntry2->start->toDateTimeString());
|
||||
$this->assertSame('2024-03-04 10:23:01', $timeEntry2->end->toDateTimeString());
|
||||
$this->assertTrue($timeEntry2->billable);
|
||||
$this->assertSame(! $billableDefault, $timeEntry2->billable);
|
||||
$this->assertTrue($timeEntry2->is_imported);
|
||||
$this->assertSame([], $timeEntry2->tags);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ async function getConfig() {
|
||||
const additionalPlugins = await collectModulePlugins('extensions');
|
||||
|
||||
return defineConfig({
|
||||
base: './',
|
||||
build: {
|
||||
sourcemap: true, // Source map generation must be turned on
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user