mirror of
https://github.com/kestra-io/kestra.git
synced 2025-12-30 03:00:23 -05:00
Compare commits
1 Commits
fix/wrong_
...
run-develo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9575cc1c87 |
@@ -93,7 +93,7 @@ public class Property<T> {
|
|||||||
* @return a new {@link Property} without a pre-rendered value
|
* @return a new {@link Property} without a pre-rendered value
|
||||||
*/
|
*/
|
||||||
public Property<T> skipCache() {
|
public Property<T> skipCache() {
|
||||||
return new Property<>(expression, true);
|
return Property.ofExpression(expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -32,12 +32,10 @@ public class NamespaceFilesUtils {
|
|||||||
private ExecutorsUtils executorsUtils;
|
private ExecutorsUtils executorsUtils;
|
||||||
|
|
||||||
private ExecutorService executorService;
|
private ExecutorService executorService;
|
||||||
private int maxThreads;
|
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void postConstruct() {
|
public void postConstruct() {
|
||||||
this.maxThreads = Math.max(Runtime.getRuntime().availableProcessors() * 4, 32);
|
this.executorService = executorsUtils.maxCachedThreadPool(Math.max(Runtime.getRuntime().availableProcessors() * 4, 32), "namespace-file");
|
||||||
this.executorService = executorsUtils.maxCachedThreadPool(maxThreads, "namespace-file");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadNamespaceFiles(
|
public void loadNamespaceFiles(
|
||||||
@@ -65,11 +63,7 @@ public class NamespaceFilesUtils {
|
|||||||
matchedNamespaceFiles.addAll(files);
|
matchedNamespaceFiles.addAll(files);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use half of the available threads to avoid impacting concurrent tasks
|
|
||||||
int parallelism = maxThreads / 2;
|
|
||||||
Flux.fromIterable(matchedNamespaceFiles)
|
Flux.fromIterable(matchedNamespaceFiles)
|
||||||
.parallel(parallelism)
|
|
||||||
.runOn(Schedulers.fromExecutorService(executorService))
|
|
||||||
.doOnNext(throwConsumer(nsFile -> {
|
.doOnNext(throwConsumer(nsFile -> {
|
||||||
InputStream content = runContext.storage().getFile(nsFile.uri());
|
InputStream content = runContext.storage().getFile(nsFile.uri());
|
||||||
Path path = folderPerNamespace ?
|
Path path = folderPerNamespace ?
|
||||||
@@ -77,7 +71,7 @@ public class NamespaceFilesUtils {
|
|||||||
Path.of(nsFile.path());
|
Path.of(nsFile.path());
|
||||||
runContext.workingDir().putFile(path, content, fileExistComportment);
|
runContext.workingDir().putFile(path, content, fileExistComportment);
|
||||||
}))
|
}))
|
||||||
.sequential()
|
.publishOn(Schedulers.fromExecutorService(executorService))
|
||||||
.blockLast();
|
.blockLast();
|
||||||
|
|
||||||
Duration duration = stopWatch.getDuration();
|
Duration duration = stopWatch.getDuration();
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ public class LoopUntil extends Task implements FlowableTask<LoopUntil.Output> {
|
|||||||
|
|
||||||
public Instant nextExecutionDate(RunContext runContext, Execution execution, TaskRun parentTaskRun) throws IllegalVariableEvaluationException {
|
public Instant nextExecutionDate(RunContext runContext, Execution execution, TaskRun parentTaskRun) throws IllegalVariableEvaluationException {
|
||||||
if (!this.reachedMaximums(runContext, execution, parentTaskRun, false)) {
|
if (!this.reachedMaximums(runContext, execution, parentTaskRun, false)) {
|
||||||
String continueLoop = runContext.render(this.condition).skipCache().as(String.class).orElse(null);
|
String continueLoop = runContext.render(this.condition).as(String.class).orElse(null);
|
||||||
if (!TruthUtils.isTruthy(continueLoop)) {
|
if (!TruthUtils.isTruthy(continueLoop)) {
|
||||||
return Instant.now().plus(runContext.render(this.getCheckFrequency().getInterval()).as(Duration.class).orElseThrow());
|
return Instant.now().plus(runContext.render(this.getCheckFrequency().getInterval()).as(Duration.class).orElseThrow());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ public class Switch extends Task implements FlowableTask<Switch.Output> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String rendererValue(RunContext runContext) throws IllegalVariableEvaluationException {
|
private String rendererValue(RunContext runContext) throws IllegalVariableEvaluationException {
|
||||||
return runContext.render(this.value).skipCache().as(String.class).orElseThrow();
|
return runContext.render(this.value).as(String.class).orElseThrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
package io.kestra.plugin.core.flow;
|
package io.kestra.plugin.core.flow;
|
||||||
|
|
||||||
import static io.kestra.core.tenant.TenantService.MAIN_TENANT;
|
import static io.kestra.core.tenant.TenantService.MAIN_TENANT;
|
||||||
import static org.assertj.core.api.Assertions.as;
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import io.kestra.core.junit.annotations.ExecuteFlow;
|
|
||||||
import io.kestra.core.junit.annotations.KestraTest;
|
import io.kestra.core.junit.annotations.KestraTest;
|
||||||
import io.kestra.core.junit.annotations.LoadFlows;
|
import io.kestra.core.junit.annotations.LoadFlows;
|
||||||
import io.kestra.core.models.executions.Execution;
|
import io.kestra.core.models.executions.Execution;
|
||||||
@@ -102,14 +100,4 @@ class SwitchTest {
|
|||||||
|
|
||||||
assertThat(execution.getState().getCurrent()).isEqualTo(State.Type.FAILED);
|
assertThat(execution.getState().getCurrent()).isEqualTo(State.Type.FAILED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
@ExecuteFlow("flows/valids/switch-in-concurrent-loop.yaml")
|
|
||||||
void switchInConcurrentLoop(Execution execution) {
|
|
||||||
assertThat(execution.getState().getCurrent()).isEqualTo(State.Type.SUCCESS);
|
|
||||||
assertThat(execution.getTaskRunList()).hasSize(5);
|
|
||||||
// we check that OOMCRM_EB_DD_000 and OOMCRM_EB_DD_001 have been processed once
|
|
||||||
assertThat(execution.getTaskRunList().stream().filter(t -> t.getTaskId().equals("OOMCRM_EB_DD_000")).count()).isEqualTo(1);
|
|
||||||
assertThat(execution.getTaskRunList().stream().filter(t -> t.getTaskId().equals("OOMCRM_EB_DD_001")).count()).isEqualTo(1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
id: switch-in-concurrent-loop
|
|
||||||
namespace: io.kestra.tests
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- id: iterate_and_check_name
|
|
||||||
type: io.kestra.plugin.core.flow.ForEach
|
|
||||||
tasks:
|
|
||||||
- id: switch
|
|
||||||
type: io.kestra.plugin.core.flow.Switch
|
|
||||||
value: "{{ taskrun.value }}"
|
|
||||||
cases:
|
|
||||||
"Alice":
|
|
||||||
- id: OOMCRM_EB_DD_000
|
|
||||||
type: io.kestra.plugin.core.log.Log
|
|
||||||
message: Alice
|
|
||||||
"Bob":
|
|
||||||
- id: OOMCRM_EB_DD_001
|
|
||||||
type: io.kestra.plugin.core.log.Log
|
|
||||||
message: Bob
|
|
||||||
|
|
||||||
values: ["Alice", "Bob"]
|
|
||||||
|
|
||||||
concurrencyLimit: 0
|
|
||||||
@@ -13,19 +13,18 @@ tasks:
|
|||||||
- io.test.second
|
- io.test.second
|
||||||
- io.test.third
|
- io.test.third
|
||||||
enabled: true
|
enabled: true
|
||||||
folderPerNamespace: true
|
|
||||||
exclude:
|
exclude:
|
||||||
- /ignore/**
|
- /ignore/**
|
||||||
tasks:
|
tasks:
|
||||||
- id: t1
|
- id: t1
|
||||||
type: io.kestra.core.tasks.test.Read
|
type: io.kestra.core.tasks.test.Read
|
||||||
path: "/io.test.third/test/a/b/c/1.txt"
|
path: "/test/a/b/c/1.txt"
|
||||||
- id: t2
|
- id: t2
|
||||||
type: io.kestra.core.tasks.test.Read
|
type: io.kestra.core.tasks.test.Read
|
||||||
path: "/io.test.second/a/b/c/2.txt"
|
path: "/a/b/c/2.txt"
|
||||||
- id: t3
|
- id: t3
|
||||||
type: io.kestra.core.tasks.test.Read
|
type: io.kestra.core.tasks.test.Read
|
||||||
path: "/io.test.first/a/b/3.txt"
|
path: "/a/b/3.txt"
|
||||||
- id: t4
|
- id: t4
|
||||||
type: io.kestra.core.tasks.test.Read
|
type: io.kestra.core.tasks.test.Read
|
||||||
path: "/ignore/4.txt"
|
path: "/ignore/4.txt"
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ public class MysqlQueue<T> extends JdbcQueue<T> {
|
|||||||
AbstractJdbcRepository.field("offset")
|
AbstractJdbcRepository.field("offset")
|
||||||
)
|
)
|
||||||
// force using the dedicated index, or it made a scan of the PK index
|
// force using the dedicated index, or it made a scan of the PK index
|
||||||
.from(this.table.useIndex("ix_type__offset"))
|
.from(this.table.useIndex("ix_type__consumers"))
|
||||||
.where(AbstractJdbcRepository.field("type").eq(queueType()))
|
.where(AbstractJdbcRepository.field("type").eq(queueType()))
|
||||||
.and(DSL.or(List.of(
|
.and(DSL.or(List.of(
|
||||||
AbstractJdbcRepository.field("consumers").isNull(),
|
AbstractJdbcRepository.field("consumers").isNull(),
|
||||||
|
|||||||
@@ -658,16 +658,21 @@ public class JdbcExecutor implements ExecutorInterface {
|
|||||||
workerTaskResults.add(new WorkerTaskResult(taskRun));
|
workerTaskResults.add(new WorkerTaskResult(taskRun));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// flowable attempt state transition to running
|
/// flowable attempt state transition to running
|
||||||
if (workerTask.getTask().isFlowable()) {
|
if (workerTask.getTask().isFlowable()) {
|
||||||
TaskRun updatedTaskRun = workerTask.getTaskRun()
|
List<TaskRunAttempt> attempts = Optional.ofNullable(workerTask.getTaskRun().getAttempts())
|
||||||
.withAttempts(
|
.map(ArrayList::new)
|
||||||
List.of(
|
.orElseGet(ArrayList::new);
|
||||||
|
|
||||||
|
|
||||||
|
attempts.add(
|
||||||
TaskRunAttempt.builder()
|
TaskRunAttempt.builder()
|
||||||
.state(new State().withState(State.Type.RUNNING))
|
.state(new State().withState(State.Type.RUNNING))
|
||||||
.build()
|
.build()
|
||||||
)
|
);
|
||||||
)
|
|
||||||
|
TaskRun updatedTaskRun = workerTask.getTaskRun()
|
||||||
|
.withAttempts(attempts)
|
||||||
.withState(State.Type.RUNNING);
|
.withState(State.Type.RUNNING);
|
||||||
|
|
||||||
workerTaskResults.add(new WorkerTaskResult(updatedTaskRun));
|
workerTaskResults.add(new WorkerTaskResult(updatedTaskRun));
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class DockerService {
|
public class DockerService {
|
||||||
|
// DDDDDDD
|
||||||
public static DockerClient client(DockerClientConfig dockerClientConfig) {
|
public static DockerClient client(DockerClientConfig dockerClientConfig) {
|
||||||
DockerHttpClient dockerHttpClient = new ApacheDockerHttpClient.Builder()
|
DockerHttpClient dockerHttpClient = new ApacheDockerHttpClient.Builder()
|
||||||
.dockerHost(dockerClientConfig.getDockerHost())
|
.dockerHost(dockerClientConfig.getDockerHost())
|
||||||
|
|||||||
8
ui/package-lock.json
generated
8
ui/package-lock.json
generated
@@ -10,7 +10,7 @@
|
|||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@js-joda/core": "^5.6.5",
|
"@js-joda/core": "^5.6.5",
|
||||||
"@kestra-io/ui-libs": "^0.0.264",
|
"@kestra-io/ui-libs": "^0.0.263",
|
||||||
"@vue-flow/background": "^1.3.2",
|
"@vue-flow/background": "^1.3.2",
|
||||||
"@vue-flow/controls": "^1.1.2",
|
"@vue-flow/controls": "^1.1.2",
|
||||||
"@vue-flow/core": "^1.47.0",
|
"@vue-flow/core": "^1.47.0",
|
||||||
@@ -2829,9 +2829,9 @@
|
|||||||
"license": "BSD-3-Clause"
|
"license": "BSD-3-Clause"
|
||||||
},
|
},
|
||||||
"node_modules/@kestra-io/ui-libs": {
|
"node_modules/@kestra-io/ui-libs": {
|
||||||
"version": "0.0.264",
|
"version": "0.0.263",
|
||||||
"resolved": "https://registry.npmjs.org/@kestra-io/ui-libs/-/ui-libs-0.0.264.tgz",
|
"resolved": "https://registry.npmjs.org/@kestra-io/ui-libs/-/ui-libs-0.0.263.tgz",
|
||||||
"integrity": "sha512-yUZDNaE0wUPOuEq/FL/TQBRd1fTV2dyM8s+VcGRjNSM1uv1uZcsSHro56/heHQx17lo00FDcPT7BMKEifrVhBg==",
|
"integrity": "sha512-j1rWqcQAK2CudNBkcDPjUXyaGFeBzJ7QEhPKFAbleHSw0N3QFu/iy0rFZxJNIMWRi1mGZBh74D6vL0OqQJkT2Q==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nuxtjs/mdc": "^0.17.3",
|
"@nuxtjs/mdc": "^0.17.3",
|
||||||
"@popperjs/core": "^2.11.8",
|
"@popperjs/core": "^2.11.8",
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@js-joda/core": "^5.6.5",
|
"@js-joda/core": "^5.6.5",
|
||||||
"@kestra-io/ui-libs": "^0.0.264",
|
"@kestra-io/ui-libs": "^0.0.263",
|
||||||
"@vue-flow/background": "^1.3.2",
|
"@vue-flow/background": "^1.3.2",
|
||||||
"@vue-flow/controls": "^1.1.2",
|
"@vue-flow/controls": "^1.1.2",
|
||||||
"@vue-flow/core": "^1.47.0",
|
"@vue-flow/core": "^1.47.0",
|
||||||
|
|||||||
@@ -87,7 +87,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
<div class="password-requirements mb-4">
|
<div class="password-requirements mb-4">
|
||||||
<el-text>
|
<el-text>
|
||||||
{{ t('setup.form.password_requirements') }}
|
8+ chars, 1 upper, 1 number
|
||||||
</el-text>
|
</el-text>
|
||||||
</div>
|
</div>
|
||||||
</el-form>
|
</el-form>
|
||||||
@@ -502,7 +502,7 @@
|
|||||||
localStorage.removeItem("basicAuthUserCreated")
|
localStorage.removeItem("basicAuthUserCreated")
|
||||||
localStorage.setItem("basicAuthSetupCompletedAt", new Date().toISOString())
|
localStorage.setItem("basicAuthSetupCompletedAt", new Date().toISOString())
|
||||||
|
|
||||||
router.push({name: "welcome"})
|
router.push({name: "login"})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ $checkbox-checked-color: #8405FF;
|
|||||||
|
|
||||||
.el-text {
|
.el-text {
|
||||||
color: var(--ks-content-tertiary);
|
color: var(--ks-content-tertiary);
|
||||||
font-size: 12px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ import Utils from "../../../utils/utils";
|
|||||||
import {cssVariable, State} from "@kestra-io/ui-libs";
|
import {cssVariable, State} from "@kestra-io/ui-libs";
|
||||||
import {getSchemeValue} from "../../../utils/scheme";
|
import {getSchemeValue} from "../../../utils/scheme";
|
||||||
|
|
||||||
import {useMiscStore} from "override/stores/misc";
|
|
||||||
|
|
||||||
export function tooltip(tooltipModel: {
|
export function tooltip(tooltipModel: {
|
||||||
title?: string[];
|
title?: string[];
|
||||||
body?: { lines: string[] }[];
|
body?: { lines: string[] }[];
|
||||||
@@ -117,7 +115,7 @@ export function extractState(value: any) {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function chartClick(moment: any, router: any, route: any, event: any, parsedData: any, elements: any, type = "label", filters: Record<string, any> = {}) {
|
export function chartClick(moment: any, router: any, route: any, event: any, parsedData: any, elements: any, type = "label") {
|
||||||
const query: Record<string, any> = {};
|
const query: Record<string, any> = {};
|
||||||
|
|
||||||
if (elements && parsedData) {
|
if (elements && parsedData) {
|
||||||
@@ -194,11 +192,7 @@ export function chartClick(moment: any, router: any, route: any, event: any, par
|
|||||||
params: {
|
params: {
|
||||||
tenant: route.params.tenant,
|
tenant: route.params.tenant,
|
||||||
},
|
},
|
||||||
query: {
|
query: query,
|
||||||
...query,
|
|
||||||
...filters,
|
|
||||||
"filters[timeRange][EQUALS]":useMiscStore()?.configs?.chartDefaultDuration ?? "P30D"
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,8 +49,6 @@
|
|||||||
showDefault: {type: Boolean, default: false},
|
showDefault: {type: Boolean, default: false},
|
||||||
short: {type: Boolean, default: false},
|
short: {type: Boolean, default: false},
|
||||||
execution: {type: Boolean, default: false},
|
execution: {type: Boolean, default: false},
|
||||||
flow: {type: String, default: undefined},
|
|
||||||
namespace: {type: String, default: undefined},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -155,10 +153,7 @@
|
|||||||
if (data.type === "io.kestra.plugin.core.dashboard.data.Logs" || props.execution) {
|
if (data.type === "io.kestra.plugin.core.dashboard.data.Logs" || props.execution) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
chartClick(moment, router, route, {}, parsedData.value, elements, "label", {
|
chartClick(moment, router, route, {}, parsedData.value, elements, "label");
|
||||||
...(props.namespace ? {"filters[namespace][IN]": props.namespace} : {}),
|
|
||||||
...(props.flow ? {"filters[flowId][EQUALS]": props.flow} : {})
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
}, theme.value);
|
}, theme.value);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -213,8 +213,6 @@
|
|||||||
:filters="chartFilters()"
|
:filters="chartFilters()"
|
||||||
showDefault
|
showDefault
|
||||||
short
|
short
|
||||||
:flow="scope.row.id"
|
|
||||||
:namespace="scope.row.namespace"
|
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|||||||
@@ -7,14 +7,14 @@
|
|||||||
:disabled="!playgroundStore.readyToStart"
|
:disabled="!playgroundStore.readyToStart"
|
||||||
>
|
>
|
||||||
<el-icon><Play /></el-icon>
|
<el-icon><Play /></el-icon>
|
||||||
<span>{{ $t('playground.run_task') }}</span>
|
<span>{{ t('playground.run_task') }}</span>
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<el-dropdown-menu>
|
<el-dropdown-menu>
|
||||||
<el-dropdown-item :icon="Play" @click="playgroundStore.runUntilTask(taskId)">
|
<el-dropdown-item :icon="Play" @click="playgroundStore.runUntilTask(taskId)">
|
||||||
{{ $t('playground.run_this_task') }}
|
{{ t('playground.run_this_task') }}
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
<el-dropdown-item :icon="PlayBoxMultiple" @click="playgroundStore.runUntilTask(taskId, true)">
|
<el-dropdown-item :icon="PlayBoxMultiple" @click="playgroundStore.runUntilTask(taskId, true)">
|
||||||
{{ $t('playground.run_task_and_downstream') }}
|
{{ t('playground.run_task_and_downstream') }}
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
</template>
|
</template>
|
||||||
@@ -22,10 +22,12 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import {useI18n} from "vue-i18n";
|
||||||
import {usePlaygroundStore} from "../../stores/playground";
|
import {usePlaygroundStore} from "../../stores/playground";
|
||||||
import Play from "vue-material-design-icons/Play.vue";
|
import Play from "vue-material-design-icons/Play.vue";
|
||||||
import PlayBoxMultiple from "vue-material-design-icons/PlayBoxMultiple.vue";
|
import PlayBoxMultiple from "vue-material-design-icons/PlayBoxMultiple.vue";
|
||||||
|
|
||||||
|
const {t} = useI18n();
|
||||||
const playgroundStore = usePlaygroundStore();
|
const playgroundStore = usePlaygroundStore();
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
import {useCoreStore} from "../../stores/core";
|
import {useCoreStore} from "../../stores/core";
|
||||||
import {useMiscStore} from "override/stores/misc";
|
import {useMiscStore} from "override/stores/misc";
|
||||||
import {computed, onMounted} from "vue";
|
import {computed, onMounted} from "vue";
|
||||||
import {useLayoutStore} from "../../stores/layout";
|
|
||||||
|
|
||||||
const coreStore = useCoreStore();
|
const coreStore = useCoreStore();
|
||||||
const miscStore = useMiscStore();
|
const miscStore = useMiscStore();
|
||||||
@@ -23,9 +22,7 @@
|
|||||||
document.getElementsByTagName("html")[0].classList.remove(collapse ? "menu-not-collapsed" : "menu-collapsed");
|
document.getElementsByTagName("html")[0].classList.remove(collapse ? "menu-not-collapsed" : "menu-collapsed");
|
||||||
}
|
}
|
||||||
|
|
||||||
const layoutStore = useLayoutStore();
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
onMenuCollapse(Boolean(layoutStore.sideMenuCollapsed))
|
onMenuCollapse(localStorage.getItem("menuCollapsed") === "true")
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {onUpdated, computed, h, watch} from "vue";
|
import {onUpdated, ref, computed, h, watch} from "vue";
|
||||||
import {useI18n} from "vue-i18n";
|
import {useI18n} from "vue-i18n";
|
||||||
import {useRoute} from "vue-router";
|
import {useRoute} from "vue-router";
|
||||||
import {useMediaQuery} from "@vueuse/core";
|
import {useMediaQuery} from "@vueuse/core";
|
||||||
@@ -118,10 +118,7 @@
|
|||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
const collapsed = computed({
|
const collapsed = ref(localStorage.getItem("menuCollapsed") === "true")
|
||||||
get: () => layoutStore.sideMenuCollapsed,
|
|
||||||
set: (v: boolean) => layoutStore.setSideMenuCollapsed(v),
|
|
||||||
})
|
|
||||||
|
|
||||||
const isSmallScreen = useMediaQuery("(max-width: 768px)")
|
const isSmallScreen = useMediaQuery("(max-width: 768px)")
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,10 @@ const handleAuthError = (error, to) => {
|
|||||||
|
|
||||||
initApp(app, routes, null, en).then(({router, piniaStore}) => {
|
initApp(app, routes, null, en).then(({router, piniaStore}) => {
|
||||||
router.beforeEach(async (to, from, next) => {
|
router.beforeEach(async (to, from, next) => {
|
||||||
|
if (to.meta?.anonymous === true) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
if(to.path === from.path && to.query === from.query) {
|
if(to.path === from.path && to.query === from.query) {
|
||||||
return next(); // Prevent navigation if the path and query are the same
|
return next(); // Prevent navigation if the path and query are the same
|
||||||
}
|
}
|
||||||
@@ -41,28 +45,13 @@ initApp(app, routes, null, en).then(({router, piniaStore}) => {
|
|||||||
if (validationErrors?.length > 0) {
|
if (validationErrors?.length > 0) {
|
||||||
// Creds exist in config but failed validation
|
// Creds exist in config but failed validation
|
||||||
// Route to login to show errors
|
// Route to login to show errors
|
||||||
if (to.name === "login") {
|
|
||||||
return next();
|
|
||||||
}
|
|
||||||
|
|
||||||
return next({name: "login"})
|
return next({name: "login"})
|
||||||
} else {
|
} else {
|
||||||
// No creds in config - redirect to set it up
|
// No creds in config - redirect to set it up
|
||||||
if (to.name === "setup") {
|
|
||||||
return next();
|
|
||||||
}
|
|
||||||
|
|
||||||
return next({name: "setup"})
|
return next({name: "setup"})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (to.meta?.anonymous === true) {
|
|
||||||
if (to.name === "setup") {
|
|
||||||
return next({name: "login"});
|
|
||||||
}
|
|
||||||
return next();
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasCredentials = BasicAuth.isLoggedIn()
|
const hasCredentials = BasicAuth.isLoggedIn()
|
||||||
|
|
||||||
if (!hasCredentials) {
|
if (!hasCredentials) {
|
||||||
@@ -103,6 +92,6 @@ initApp(app, routes, null, en).then(({router, piniaStore}) => {
|
|||||||
}, null, router, true);
|
}, null, router, true);
|
||||||
|
|
||||||
// mount
|
// mount
|
||||||
router.isReady().then(() => app.mount("#app"))
|
app.mount("#app")
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -12,13 +12,7 @@ export const useLayoutStore = defineStore("layout", {
|
|||||||
topNavbar: undefined,
|
topNavbar: undefined,
|
||||||
envName: localStorage.getItem("envName") || undefined,
|
envName: localStorage.getItem("envName") || undefined,
|
||||||
envColor: localStorage.getItem("envColor") || undefined,
|
envColor: localStorage.getItem("envColor") || undefined,
|
||||||
sideMenuCollapsed: (() => {
|
sideMenuCollapsed: localStorage.getItem("menuCollapsed") === "true",
|
||||||
if (typeof window === "undefined") {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return localStorage.getItem("menuCollapsed") === "true" || window.matchMedia("(max-width: 768px)").matches;
|
|
||||||
})(),
|
|
||||||
}),
|
}),
|
||||||
getters: {},
|
getters: {},
|
||||||
actions: {
|
actions: {
|
||||||
|
|||||||
@@ -1612,8 +1612,7 @@
|
|||||||
"email": "E-Mail",
|
"email": "E-Mail",
|
||||||
"firstName": "Vorname",
|
"firstName": "Vorname",
|
||||||
"lastName": "Nachname",
|
"lastName": "Nachname",
|
||||||
"password": "Passwort",
|
"password": "Passwort"
|
||||||
"password_requirements": "Das Passwort muss mindestens 8 Zeichen lang sein und mindestens 1 Großbuchstaben und 1 Zahl enthalten."
|
|
||||||
},
|
},
|
||||||
"login": "Anmelden",
|
"login": "Anmelden",
|
||||||
"logout": "Abmelden",
|
"logout": "Abmelden",
|
||||||
|
|||||||
@@ -1477,8 +1477,7 @@
|
|||||||
"email": "Email",
|
"email": "Email",
|
||||||
"firstName": "First Name",
|
"firstName": "First Name",
|
||||||
"lastName": "Last Name",
|
"lastName": "Last Name",
|
||||||
"password": "Password",
|
"password": "Password"
|
||||||
"password_requirements": "Password must be at least 8 characters long and include at least 1 uppercase letter and 1 number."
|
|
||||||
},
|
},
|
||||||
"validation": {
|
"validation": {
|
||||||
"email_required": "Email is required",
|
"email_required": "Email is required",
|
||||||
|
|||||||
@@ -1612,8 +1612,7 @@
|
|||||||
"email": "Correo electrónico",
|
"email": "Correo electrónico",
|
||||||
"firstName": "Nombre",
|
"firstName": "Nombre",
|
||||||
"lastName": "Apellido",
|
"lastName": "Apellido",
|
||||||
"password": "Contraseña",
|
"password": "Contraseña"
|
||||||
"password_requirements": "La contraseña debe tener al menos 8 caracteres y contener al menos 1 letra mayúscula y 1 número."
|
|
||||||
},
|
},
|
||||||
"login": "Iniciar sesión",
|
"login": "Iniciar sesión",
|
||||||
"logout": "Cerrar sesión",
|
"logout": "Cerrar sesión",
|
||||||
|
|||||||
@@ -1612,8 +1612,7 @@
|
|||||||
"email": "E-mail",
|
"email": "E-mail",
|
||||||
"firstName": "Prénom",
|
"firstName": "Prénom",
|
||||||
"lastName": "Nom de famille",
|
"lastName": "Nom de famille",
|
||||||
"password": "Mot de passe",
|
"password": "Mot de passe"
|
||||||
"password_requirements": "Le mot de passe doit comporter au moins 8 caractères, inclure au moins 1 lettre majuscule et 1 chiffre."
|
|
||||||
},
|
},
|
||||||
"login": "Connexion",
|
"login": "Connexion",
|
||||||
"logout": "Déconnexion",
|
"logout": "Déconnexion",
|
||||||
|
|||||||
@@ -1612,8 +1612,7 @@
|
|||||||
"email": "ईमेल",
|
"email": "ईमेल",
|
||||||
"firstName": "पहला नाम",
|
"firstName": "पहला नाम",
|
||||||
"lastName": "अंतिम नाम",
|
"lastName": "अंतिम नाम",
|
||||||
"password": "पासवर्ड",
|
"password": "पासवर्ड"
|
||||||
"password_requirements": "पासवर्ड कम से कम 8 अक्षरों का होना चाहिए और इसमें कम से कम 1 बड़ा अक्षर और 1 संख्या शामिल होनी चाहिए।"
|
|
||||||
},
|
},
|
||||||
"login": "लॉगिन",
|
"login": "लॉगिन",
|
||||||
"logout": "लॉगआउट",
|
"logout": "लॉगआउट",
|
||||||
|
|||||||
@@ -1612,8 +1612,7 @@
|
|||||||
"email": "Email",
|
"email": "Email",
|
||||||
"firstName": "Nome",
|
"firstName": "Nome",
|
||||||
"lastName": "Cognome",
|
"lastName": "Cognome",
|
||||||
"password": "Password",
|
"password": "Password"
|
||||||
"password_requirements": "La password deve essere lunga almeno 8 caratteri e includere almeno 1 lettera maiuscola e 1 numero."
|
|
||||||
},
|
},
|
||||||
"login": "Accedi",
|
"login": "Accedi",
|
||||||
"logout": "Logout",
|
"logout": "Logout",
|
||||||
|
|||||||
@@ -1612,8 +1612,7 @@
|
|||||||
"email": "メール",
|
"email": "メール",
|
||||||
"firstName": "名",
|
"firstName": "名",
|
||||||
"lastName": "姓",
|
"lastName": "姓",
|
||||||
"password": "パスワード",
|
"password": "パスワード"
|
||||||
"password_requirements": "パスワードは8文字以上で、少なくとも1つの大文字と1つの数字を含める必要があります。"
|
|
||||||
},
|
},
|
||||||
"login": "ログイン",
|
"login": "ログイン",
|
||||||
"logout": "ログアウト",
|
"logout": "ログアウト",
|
||||||
|
|||||||
@@ -1612,8 +1612,7 @@
|
|||||||
"email": "이메일",
|
"email": "이메일",
|
||||||
"firstName": "이름",
|
"firstName": "이름",
|
||||||
"lastName": "성씨",
|
"lastName": "성씨",
|
||||||
"password": "비밀번호",
|
"password": "비밀번호"
|
||||||
"password_requirements": "비밀번호는 최소 8자 이상이어야 하며, 최소 1개의 대문자와 1개의 숫자를 포함해야 합니다."
|
|
||||||
},
|
},
|
||||||
"login": "로그인",
|
"login": "로그인",
|
||||||
"logout": "로그아웃",
|
"logout": "로그아웃",
|
||||||
|
|||||||
@@ -1612,8 +1612,7 @@
|
|||||||
"email": "Email",
|
"email": "Email",
|
||||||
"firstName": "Imię",
|
"firstName": "Imię",
|
||||||
"lastName": "Nazwisko",
|
"lastName": "Nazwisko",
|
||||||
"password": "Hasło",
|
"password": "Hasło"
|
||||||
"password_requirements": "Hasło musi mieć co najmniej 8 znaków i zawierać co najmniej 1 wielką literę oraz 1 cyfrę."
|
|
||||||
},
|
},
|
||||||
"login": "Zaloguj się",
|
"login": "Zaloguj się",
|
||||||
"logout": "Wyloguj się",
|
"logout": "Wyloguj się",
|
||||||
|
|||||||
@@ -1612,8 +1612,7 @@
|
|||||||
"email": "Email",
|
"email": "Email",
|
||||||
"firstName": "Nome",
|
"firstName": "Nome",
|
||||||
"lastName": "Sobrenome",
|
"lastName": "Sobrenome",
|
||||||
"password": "Senha",
|
"password": "Senha"
|
||||||
"password_requirements": "A senha deve ter pelo menos 8 caracteres e incluir pelo menos 1 letra maiúscula e 1 número."
|
|
||||||
},
|
},
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
"logout": "Sair",
|
"logout": "Sair",
|
||||||
|
|||||||
@@ -1612,8 +1612,7 @@
|
|||||||
"email": "Email",
|
"email": "Email",
|
||||||
"firstName": "Nome",
|
"firstName": "Nome",
|
||||||
"lastName": "Sobrenome",
|
"lastName": "Sobrenome",
|
||||||
"password": "Senha",
|
"password": "Senha"
|
||||||
"password_requirements": "A senha deve ter pelo menos 8 caracteres e incluir pelo menos 1 letra maiúscula e 1 número."
|
|
||||||
},
|
},
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
"logout": "Sair",
|
"logout": "Sair",
|
||||||
|
|||||||
@@ -1612,8 +1612,7 @@
|
|||||||
"email": "Электронная почта",
|
"email": "Электронная почта",
|
||||||
"firstName": "Имя",
|
"firstName": "Имя",
|
||||||
"lastName": "Фамилия",
|
"lastName": "Фамилия",
|
||||||
"password": "Пароль",
|
"password": "Пароль"
|
||||||
"password_requirements": "Пароль должен содержать не менее 8 символов, включая как минимум 1 заглавную букву и 1 цифру."
|
|
||||||
},
|
},
|
||||||
"login": "Войти",
|
"login": "Войти",
|
||||||
"logout": "Выход",
|
"logout": "Выход",
|
||||||
|
|||||||
@@ -1612,8 +1612,7 @@
|
|||||||
"email": "电子邮件",
|
"email": "电子邮件",
|
||||||
"firstName": "名字",
|
"firstName": "名字",
|
||||||
"lastName": "姓氏",
|
"lastName": "姓氏",
|
||||||
"password": "密码",
|
"password": "密码"
|
||||||
"password_requirements": "密码必须至少包含8个字符,并且至少包含1个大写字母和1个数字。"
|
|
||||||
},
|
},
|
||||||
"login": "登录",
|
"login": "登录",
|
||||||
"logout": "注销",
|
"logout": "注销",
|
||||||
|
|||||||
Reference in New Issue
Block a user