mirror of
https://github.com/kestra-io/kestra.git
synced 2025-12-19 18:05:41 -05:00
feat(ui): refactor the schedule ui
This commit is contained in:
committed by
Ludovic DEHON
parent
8f88d024cb
commit
8a2ffba2d1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"esversion": 6,
|
||||
"esversion": 9,
|
||||
"asi": true,
|
||||
"curly": true,
|
||||
"eqeqeq": true,
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
</div>
|
||||
</template>
|
||||
<span>{{content.message || content}}</span>
|
||||
<b-table v-if="items && items.length > 0" striped hover :items="items"></b-table>
|
||||
<b-table class="mt-2 mb-0" small bordered v-if="items && items.length > 0" striped hover
|
||||
:items="items"></b-table>
|
||||
</b-toast>
|
||||
</template>
|
||||
<script>
|
||||
@@ -51,3 +52,9 @@ export default {
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import "../styles/variable";
|
||||
table {
|
||||
background-color: $white;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -17,8 +17,7 @@
|
||||
</template>
|
||||
</b-table>
|
||||
<div v-if="execution.inputs">
|
||||
<hr />
|
||||
<h3>{{$t('inputs')}}</h3>
|
||||
<h5>{{$t('inputs')}}</h5>
|
||||
<b-table
|
||||
responsive="xl"
|
||||
striped
|
||||
@@ -41,6 +40,23 @@
|
||||
</template>
|
||||
</b-table>
|
||||
</div>
|
||||
|
||||
<div v-if="variables.length > 0" class="mt-4">
|
||||
<h5>{{$t('variables')}}</h5>
|
||||
<b-table
|
||||
responsive="xl"
|
||||
striped
|
||||
hover
|
||||
bordered
|
||||
:items="this.variables"
|
||||
:fields="fields"
|
||||
class="mb-0"
|
||||
>
|
||||
<template v-slot:cell(key)="row">
|
||||
<code>{{row.item.key}}</code>
|
||||
</template>
|
||||
</b-table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
@@ -63,6 +79,14 @@ export default {
|
||||
},
|
||||
restart() {
|
||||
this.$emit("follow");
|
||||
},
|
||||
flat(object) {
|
||||
return Object.assign({}, ...function _flatten(child, path = []) {
|
||||
return [].concat(...Object.keys(child).map(key => typeof child[key] === 'object'
|
||||
? _flatten(child[key], path.concat([key]))
|
||||
: ({ [path.concat([key]).join(".")] : child[key] })
|
||||
));
|
||||
}(object));
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -133,9 +157,24 @@ export default {
|
||||
for (const key in this.execution.inputs) {
|
||||
inputs.push({ key, value: this.execution.inputs[key] });
|
||||
}
|
||||
|
||||
console.log(inputs);
|
||||
return inputs;
|
||||
},
|
||||
variables() {
|
||||
const variables = [];
|
||||
|
||||
if (this.execution.variables !== undefined) {
|
||||
const flat = this.flat(this.execution.variables);
|
||||
for (const key in flat) {
|
||||
variables.push({ key, value: flat[key] });
|
||||
}
|
||||
}
|
||||
|
||||
return variables;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -42,6 +42,7 @@ import BottomLine from "../layout/BottomLine";
|
||||
import RouteContext from "../../mixins/routeContext";
|
||||
import permission from "../../models/permission";
|
||||
import action from "../../models/action";
|
||||
import { canSaveFlow, saveFlow } from "../../utils/flow";
|
||||
|
||||
export default {
|
||||
mixins: [RouteContext],
|
||||
@@ -72,13 +73,7 @@ export default {
|
||||
);
|
||||
},
|
||||
canSave() {
|
||||
return (
|
||||
this.isEdit && this.user &&
|
||||
this.user.isAllowed(permission.FLOW, action.UPDATE, this.content.namespace)
|
||||
) || (
|
||||
!this.isEdit && this.user &&
|
||||
this.user.isAllowed(permission.FLOW, action.CREATE, this.content.namespace)
|
||||
);
|
||||
return canSaveFlow(true, this.user, this.content);
|
||||
},
|
||||
canDelete() {
|
||||
return this.isEdit && this.user &&
|
||||
@@ -157,13 +152,8 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
this.$store
|
||||
.dispatch("flow/saveFlow", {
|
||||
flow
|
||||
})
|
||||
.then(() => {
|
||||
this.$toast().success({message: this.$t("flow update ok")});
|
||||
})
|
||||
|
||||
saveFlow(this, flow)
|
||||
.finally(() => {
|
||||
this.loadFlow();
|
||||
});
|
||||
|
||||
@@ -110,7 +110,14 @@ export default {
|
||||
});
|
||||
}
|
||||
|
||||
if (this.user && this.flow && this.user.isAllowed(permission.EXECUTION, action.UPDATE, this.flow.namespace)) {
|
||||
if (this.user && this.flow && this.user.isAllowed(permission.EXECUTION, action.CREATE, this.flow.namespace)) {
|
||||
tabs.push({
|
||||
tab: "execution-configuration",
|
||||
title: title("trigger")
|
||||
});
|
||||
}
|
||||
|
||||
if (this.user && this.flow && this.user.isAllowed(permission.FLOW, action.UPDATE, this.flow.namespace)) {
|
||||
tabs.push({
|
||||
tab: "data-source",
|
||||
title: title("source"),
|
||||
@@ -118,11 +125,12 @@ export default {
|
||||
});
|
||||
|
||||
tabs.push({
|
||||
tab: "execution-configuration",
|
||||
title: title("trigger")
|
||||
tab: "schedule",
|
||||
title: title("schedule"),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
return tabs;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,94 +1,73 @@
|
||||
<template>
|
||||
<div v-if="flow">
|
||||
<b-row>
|
||||
<b-col md="8">
|
||||
<b-list-group>
|
||||
<schedule-item
|
||||
@remove="remove"
|
||||
:schedule="schedule"
|
||||
:index="x"
|
||||
v-for="(schedule, x) in triggers"
|
||||
:key="x"
|
||||
/>
|
||||
</b-list-group>
|
||||
</b-col>
|
||||
<b-col md="4">
|
||||
<b-row>
|
||||
<b-col class="text-center">
|
||||
<p>
|
||||
<small>Cron helper</small>
|
||||
</p>
|
||||
<b-table responsive :items="cronHelpData"></b-table>
|
||||
<b-table responsive :items="cronHelpTokens"></b-table>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<b-row>
|
||||
<b-col>
|
||||
<b-form-group>
|
||||
<b-btn variant="primary" @click="addSchedule">
|
||||
<plus />
|
||||
{{$t('add schedule') | cap}}
|
||||
</b-btn>
|
||||
</b-form-group>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<div>
|
||||
<b-list-group>
|
||||
<schedule-item
|
||||
@remove="remove"
|
||||
@set="set"
|
||||
:schedule="schedule"
|
||||
:index="x"
|
||||
v-for="(schedule, x) in (flow.triggers || []) "
|
||||
:key="x"
|
||||
/>
|
||||
</b-list-group>
|
||||
<bottom-line v-if="canSave">
|
||||
<ul class="navbar-nav ml-auto">
|
||||
<li class="nav-item">
|
||||
<b-button variant="primary" @click="addSchedule" v-if="canSave">
|
||||
<plus />
|
||||
{{ $t('add schedule') }}
|
||||
</b-button>
|
||||
|
||||
<b-button @click="save" v-if="canSave">
|
||||
<content-save />
|
||||
<span>{{$t('save')}}</span>
|
||||
</b-button>
|
||||
</li>
|
||||
</ul>
|
||||
</bottom-line>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { mapState } from "vuex";
|
||||
import ContentSave from "vue-material-design-icons/ContentSave";
|
||||
import Plus from "vue-material-design-icons/Plus";
|
||||
import ScheduleItem from "./ScheduleItem";
|
||||
import BottomLine from "../layout/BottomLine";
|
||||
import { canSaveFlow, saveFlow } from "../../utils/flow";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Plus,
|
||||
ScheduleItem
|
||||
},
|
||||
watch: {
|
||||
flow() {
|
||||
console.log("on flow change");
|
||||
}
|
||||
ContentSave,
|
||||
ScheduleItem,
|
||||
BottomLine
|
||||
},
|
||||
computed: {
|
||||
...mapState("flow", ["flow", "triggers"]),
|
||||
validForm() {
|
||||
return true;
|
||||
},
|
||||
|
||||
cronHelpData() {
|
||||
const helpRecord = {};
|
||||
helpRecord[this.$t("minute")] = "*";
|
||||
helpRecord[this.$t("hour")] = "*";
|
||||
helpRecord[this.$t("day (month)")] = "*";
|
||||
helpRecord[this.$t("month")] = "*";
|
||||
helpRecord[this.$t("day (week)")] = "*";
|
||||
return [helpRecord];
|
||||
},
|
||||
cronHelpTokens() {
|
||||
const helpRecord = {};
|
||||
helpRecord[this.$t("any value")] = "*";
|
||||
helpRecord[this.$t("value list separator")] = ",";
|
||||
helpRecord[this.$t("range of values")] = "-";
|
||||
helpRecord[this.$t("step values")] = "/";
|
||||
return [helpRecord];
|
||||
...mapState("flow", ["flow"]),
|
||||
...mapState("auth", ["user"]),
|
||||
canSave() {
|
||||
return canSaveFlow(true, this.user, this.flow);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
save() {
|
||||
saveFlow(this, this.flow);
|
||||
},
|
||||
set(index, schedule) {
|
||||
this.$store.commit("flow/setTrigger", {index, trigger: schedule});
|
||||
},
|
||||
remove(index) {
|
||||
this.$store.commit("flow/removeTrigger", index);
|
||||
this.$store.dispatch('flow/updateFlowTrigger')
|
||||
},
|
||||
addSchedule() {
|
||||
this.$store.commit("flow/addTrigger", {
|
||||
id: "schedule",
|
||||
cron: "0 4 * * 1,4",
|
||||
type: "org.kestra.core.models.triggers.types.Schedule"
|
||||
type: "org.kestra.core.models.triggers.types.Schedule",
|
||||
});
|
||||
this.$store.dispatch('flow/updateFlowTrigger')
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,34 +1,73 @@
|
||||
<template>
|
||||
<b-list-group-item>
|
||||
<b-row>
|
||||
<b-col md="6">
|
||||
{{schedule.cron}}
|
||||
<b-form-group>
|
||||
<b-input type="text" v-model="schedule.cron" />
|
||||
</b-form-group>
|
||||
<p class="text-danger" v-if="!isValid">{{$t('invalid schedule')}}</p>
|
||||
<p class="text-primary" v-else>{{cronHumanReadable}}</p>
|
||||
<b-btn variant="warning" @click="remove">
|
||||
<delete />Remove
|
||||
</b-btn>
|
||||
</b-col>
|
||||
<b-col md="6" class="text-center">
|
||||
<div v-if="occurences.length">
|
||||
<p class="font-weight-bold">3 Next occurences</p>
|
||||
<p v-for="(occurence, x) in occurences" :key="x">{{occurence | date('LLL:ss')}}</p>
|
||||
</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<b-form-group label-cols-sm="3" label-cols-lg="2" :label="$t('id')" :label-for="'input-id-' + index">
|
||||
<b-form-input required :id="'input-id-' + index" v-model="schedule.id"></b-form-input>
|
||||
</b-form-group>
|
||||
|
||||
<b-form-group label-cols-sm="3" label-cols-lg="2"
|
||||
:label-for="'input-cron-' + index"
|
||||
:state="isValid">
|
||||
<template v-slot:label>
|
||||
{{ $t('schedules.cron.expression')}}
|
||||
<b-link class="text-body" :id="'tooltip-' + index">
|
||||
<help />
|
||||
</b-link>
|
||||
|
||||
<b-tooltip :target="'tooltip-' + index" placement="bottom">
|
||||
<div v-if="isValid">
|
||||
<p class="font-weight-bold">3 Next occurences</p>
|
||||
|
||||
<span v-if="occurences.length">
|
||||
<span v-for="(occurence, x) in occurences" :key="x">{{occurence | date('LLL:ss')}}<br /></span>
|
||||
</span>
|
||||
</div>
|
||||
<span v-else>
|
||||
{{ $t("schedules.cron.invalid") }}
|
||||
</span>
|
||||
</b-tooltip>
|
||||
</template>
|
||||
|
||||
<b-form-input required :id="'input-cron-' + index" v-model="schedule.cron"></b-form-input>
|
||||
|
||||
<b-form-invalid-feedback>
|
||||
Enter at least 3 letters
|
||||
</b-form-invalid-feedback>
|
||||
|
||||
<b-form-text>{{ cronHumanReadable }}</b-form-text>
|
||||
</b-form-group>
|
||||
|
||||
|
||||
<b-form-group label-cols-sm="3" label-cols-lg="2" :label="$t('schedules.cron.backfilll')"
|
||||
:label-for="'input-' + index">
|
||||
<date-picker
|
||||
v-model="backfillStart"
|
||||
:required="false"
|
||||
type="datetime"
|
||||
:id="'input-' + index"
|
||||
></date-picker>
|
||||
</b-form-group>
|
||||
|
||||
<b-form-group class="mb-0 text-right">
|
||||
<b-btn variant="danger" @click="remove">
|
||||
<delete/>
|
||||
Delete
|
||||
</b-btn>
|
||||
|
||||
</b-form-group>
|
||||
</b-list-group-item>
|
||||
</template>
|
||||
<script>
|
||||
const cronstrue = require("cronstrue/i18n");
|
||||
const cronParser = require("cron-parser");
|
||||
import Delete from "vue-material-design-icons/Delete";
|
||||
import Help from "vue-material-design-icons/HelpBox";
|
||||
import DatePicker from "vue2-datepicker";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Delete
|
||||
Delete,
|
||||
Help,
|
||||
DatePicker
|
||||
},
|
||||
props: {
|
||||
schedule: {
|
||||
@@ -40,7 +79,26 @@ export default {
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
backfillStart: {
|
||||
get: function () {
|
||||
return this.schedule.backfill && this.schedule.backfill.start !== undefined ?
|
||||
this.$moment(this.schedule.backfill.start).toDate() :
|
||||
undefined;
|
||||
},
|
||||
set: function (val) {
|
||||
let current = this.schedule;
|
||||
|
||||
if (val) {
|
||||
current.backfill = {"start": this.$moment(val).format()};
|
||||
} else {
|
||||
delete current.backfill;
|
||||
}
|
||||
|
||||
this.$emit("set", this.index, current);
|
||||
}
|
||||
},
|
||||
occurences() {
|
||||
const occurences = [];
|
||||
if (!this.isValid) {
|
||||
@@ -57,7 +115,7 @@ export default {
|
||||
try {
|
||||
return cronstrue.toString(this.schedule.cron, { locale });
|
||||
} catch {
|
||||
return "invalid cron expression";
|
||||
return this.$t("schedules.cron.invalid");
|
||||
}
|
||||
},
|
||||
isValid() {
|
||||
@@ -66,17 +124,8 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
remove() {
|
||||
this.$bvModal
|
||||
.msgBoxConfirm(this.$t("Are you sure?"))
|
||||
.then(value => {
|
||||
if (value) {
|
||||
this.$emit("remove", this.index);
|
||||
}
|
||||
});
|
||||
},
|
||||
onChange() {
|
||||
this.schedule.cron = "";
|
||||
this.$emit("remove", this.index);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -12,6 +12,15 @@
|
||||
|
||||
@import '~vue2-datepicker/scss/index';
|
||||
|
||||
.mx-input {
|
||||
border-radius: $border-radius;
|
||||
}
|
||||
.form-group {
|
||||
.mx-datepicker {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@import 'styles/vue-material-custom';
|
||||
|
||||
@import '~c3/src/scss/main';
|
||||
@@ -23,4 +32,4 @@
|
||||
select {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ export default {
|
||||
flow: undefined,
|
||||
total: 0,
|
||||
dataTree: undefined,
|
||||
triggers: []
|
||||
},
|
||||
|
||||
actions: {
|
||||
@@ -55,26 +54,60 @@ export default {
|
||||
return Vue.axios.get(`/api/v1/flows/${flow.namespace}/${flow.id}/tree`).then(response => {
|
||||
commit('setDataTree', response.data.tasks)
|
||||
})
|
||||
},
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
setFlows(state, flows) {
|
||||
state.flows = flows
|
||||
},
|
||||
setFlow(state, flow) {
|
||||
state.flow = flow
|
||||
if (flow.triggers) {
|
||||
state.triggers = flow.triggers
|
||||
if (flow.triggers !== undefined) {
|
||||
flow.triggers = flow.triggers.map(trigger => {
|
||||
if (trigger.backfill === undefined) {
|
||||
trigger.backfill = {
|
||||
start: undefined
|
||||
}
|
||||
}
|
||||
|
||||
return trigger;
|
||||
})
|
||||
}
|
||||
|
||||
state.flow = {...flow}
|
||||
},
|
||||
setTriggers(state, triggers) {
|
||||
state.triggers = triggers
|
||||
setTrigger(state, {index, trigger}) {
|
||||
let flow = state.flow;
|
||||
|
||||
if (flow.triggers === undefined) {
|
||||
flow.triggers = []
|
||||
}
|
||||
|
||||
flow.triggers[index] = trigger;
|
||||
|
||||
state.flow = {...flow}
|
||||
},
|
||||
removeTrigger(state, index) {
|
||||
state.triggers.splice(index, 1);
|
||||
let flow = state.flow;
|
||||
flow.triggers.splice(index, 1);
|
||||
|
||||
state.flow = {...flow}
|
||||
},
|
||||
addTrigger(state, trigger) {
|
||||
state.triggers.push(trigger)
|
||||
let flow = state.flow;
|
||||
|
||||
if (trigger.backfill === undefined) {
|
||||
trigger.backfill = {
|
||||
start: undefined
|
||||
}
|
||||
}
|
||||
|
||||
if (flow.triggers === undefined) {
|
||||
flow.triggers = []
|
||||
}
|
||||
|
||||
flow.triggers.push(trigger)
|
||||
|
||||
state.flow = {...flow}
|
||||
},
|
||||
setTotal(state, total) {
|
||||
state.total = total
|
||||
@@ -86,9 +119,7 @@ export default {
|
||||
getters: {
|
||||
flow (state) {
|
||||
if (state.flow) {
|
||||
const flow = state.flow
|
||||
flow.triggers = state.triggers
|
||||
return flow
|
||||
return state.flow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,116 +5,116 @@
|
||||
// Color system
|
||||
//
|
||||
|
||||
$white: #fff !default;
|
||||
$gray-100: #f8f9fa !default;
|
||||
$gray-200: #eee !default;
|
||||
$gray-300: #dee2e6 !default;
|
||||
$gray-400: #ccc !default;
|
||||
$gray-500: #adb5bd !default;
|
||||
$gray-600: #888 !default;
|
||||
$gray-700: #495057 !default;
|
||||
$gray-800: #333 !default;
|
||||
$gray-900: #222 !default;
|
||||
$black: #000 !default;
|
||||
$white: #fff;
|
||||
$gray-100: #f8f9fa;
|
||||
$gray-200: #eee;
|
||||
$gray-300: #dee2e6;
|
||||
$gray-400: #ccc;
|
||||
$gray-500: #adb5bd;
|
||||
$gray-600: #888;
|
||||
$gray-700: #495057;
|
||||
$gray-800: #333;
|
||||
$gray-900: #222;
|
||||
$black: #000;
|
||||
|
||||
$blue: #1AA5DE !default;
|
||||
$indigo: #6610f2 !default;
|
||||
$purple: #6f42c1 !default;
|
||||
$pink: #e83e8c !default;
|
||||
$red: #F04124 !default;
|
||||
$orange: #fd7e14 !default;
|
||||
$yellow: #FBD10B !default;
|
||||
$green: #43ac6a !default;
|
||||
$teal: #1DBAAF !default;
|
||||
$cyan: #5bc0de !default;
|
||||
$blue: #1AA5DE;
|
||||
$indigo: #6610f2;
|
||||
$purple: #6f42c1;
|
||||
$pink: #e83e8c;
|
||||
$red: #F04124;
|
||||
$orange: #fd7e14;
|
||||
$yellow: #FBD10B;
|
||||
$green: #43ac6a;
|
||||
$teal: #1DBAAF;
|
||||
$cyan: #5bc0de;
|
||||
|
||||
$primary: $blue !default;
|
||||
$secondary: $teal !default;
|
||||
$primary: $blue;
|
||||
$secondary: $teal;
|
||||
$tertiary: $yellow;
|
||||
$success: $green !default;
|
||||
$info: $cyan !default;
|
||||
$warning: $yellow !default;
|
||||
$danger: $red !default;
|
||||
$light: $gray-200 !default;
|
||||
$dark: $gray-900 !default;
|
||||
$success: $green;
|
||||
$info: $cyan;
|
||||
$warning: $yellow;
|
||||
$danger: $red;
|
||||
$light: $gray-200;
|
||||
$dark: $gray-900;
|
||||
|
||||
$yiq-contrasted-threshold: 200 !default;
|
||||
$yiq-contrasted-threshold: 200;
|
||||
|
||||
// Components
|
||||
|
||||
$border-radius: 0px !default;
|
||||
$border-radius-lg: 4px !default;
|
||||
$border-radius-sm: 0px !default;
|
||||
$border-radius: 0px;
|
||||
$border-radius-lg: 4px;
|
||||
$border-radius-sm: 0px;
|
||||
|
||||
// Fonts
|
||||
|
||||
$font-family-sans-serif: "Open Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !default;
|
||||
$font-family-monospace: 'Source Code Pro', SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !default;
|
||||
$font-family-sans-serif: "Open Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||
$font-family-monospace: 'Source Code Pro', SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
|
||||
$font-size-base: 1rem !default;
|
||||
$font-size-xs: $font-size-base * .75 !default;
|
||||
$font-size-base: 1rem;
|
||||
$font-size-xs: $font-size-base * .75;
|
||||
|
||||
$headings-font-weight: 300 !default;
|
||||
$text-muted: $gray-700 !default;
|
||||
$headings-font-weight: 300;
|
||||
$text-muted: $gray-700;
|
||||
|
||||
// Buttons
|
||||
|
||||
$input-btn-padding-x: 0.5rem !default;
|
||||
$input-btn-padding-x: 0.5rem;
|
||||
|
||||
$btn-font-weight: 300 !default;
|
||||
$btn-font-weight: 300;
|
||||
|
||||
// Dropdowns
|
||||
|
||||
$dropdown-border-color: rgba($black, .1) !default;
|
||||
$dropdown-divider-bg: rgba($black, .1) !default;
|
||||
$dropdown-border-color: rgba($black, .1);
|
||||
$dropdown-divider-bg: rgba($black, .1);
|
||||
|
||||
// Navs
|
||||
|
||||
$nav-link-disabled-color: $gray-400 !default;
|
||||
$nav-link-disabled-color: $gray-400;
|
||||
|
||||
$nav-tabs-border-color: $dropdown-border-color !default;
|
||||
$nav-tabs-link-hover-border-color: $nav-tabs-border-color !default;
|
||||
$nav-tabs-link-active-border-color: $nav-tabs-border-color !default;
|
||||
$nav-tabs-border-color: $dropdown-border-color;
|
||||
$nav-tabs-link-hover-border-color: $nav-tabs-border-color;
|
||||
$nav-tabs-link-active-border-color: $nav-tabs-border-color;
|
||||
|
||||
// Navbar
|
||||
|
||||
$navbar-dark-color: rgba($white, .7) !default;
|
||||
$navbar-dark-hover-color: $white !default;
|
||||
$navbar-dark-color: rgba($white, .7);
|
||||
$navbar-dark-hover-color: $white;
|
||||
|
||||
// Pagination
|
||||
|
||||
$pagination-color: $gray-600 !default;
|
||||
$pagination-border-color: $nav-tabs-border-color !default;
|
||||
$pagination-color: $gray-600;
|
||||
$pagination-border-color: $nav-tabs-border-color;
|
||||
|
||||
$pagination-active-border-color: darken($primary, 5%) !default;
|
||||
$pagination-active-border-color: darken($primary, 5%);
|
||||
|
||||
|
||||
// Jumbotron
|
||||
|
||||
$jumbotron-padding: 4rem !default;
|
||||
$jumbotron-padding: 4rem;
|
||||
|
||||
// Cards
|
||||
|
||||
$card-inner-border-radius: 0px !default;
|
||||
$card-inner-border-radius: 0px;
|
||||
|
||||
// Badges
|
||||
|
||||
$badge-font-weight: 300 !default;
|
||||
$badge-padding-x: 1rem !default;
|
||||
$badge-font-weight: 300;
|
||||
$badge-padding-x: 1rem;
|
||||
|
||||
// Progress bars
|
||||
|
||||
$progress-bg: $gray-400 !default;
|
||||
$progress-bar-color: $white !default;
|
||||
$progress-bg: $gray-400;
|
||||
$progress-bar-color: $white;
|
||||
|
||||
// List group
|
||||
|
||||
$list-group-disabled-bg: $gray-200 !default;
|
||||
$list-group-disabled-bg: $gray-200;
|
||||
|
||||
// Close
|
||||
|
||||
$close-color: $gray-600 !default;
|
||||
$close-text-shadow: none !default;
|
||||
$close-color: $gray-600;
|
||||
$close-text-shadow: none;
|
||||
|
||||
// Breadcrumb
|
||||
$breadcrumb-item-padding: 0.25rem;
|
||||
$breadcrumb-item-padding: 0.25rem;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"en": {
|
||||
"id": "Id",
|
||||
"namespace": "namespace",
|
||||
"namespace": "Namespace",
|
||||
"revision": "Revision",
|
||||
"Language": "Language",
|
||||
"Set default page": "Set default page",
|
||||
@@ -96,10 +96,18 @@
|
||||
"down trend": "Decreasing",
|
||||
"flow update aborted": "Flow update aborted",
|
||||
"invalid flow": "Invalid flow",
|
||||
"add schedule": "add schedule",
|
||||
"schedule": "schedule",
|
||||
"add schedule": "Add a schedule",
|
||||
"schedule": "Schedule",
|
||||
"schedules": {
|
||||
"cron": {
|
||||
"expression": "Expression",
|
||||
"backfilll": "Backfill",
|
||||
"invalid": "Invalid cron expression"
|
||||
}
|
||||
},
|
||||
"inputs": "Inputs",
|
||||
"input": "Input",
|
||||
"variables": "Variables",
|
||||
"download": "Download"
|
||||
},
|
||||
"fr": {
|
||||
@@ -200,10 +208,18 @@
|
||||
"down trend": "En baisse",
|
||||
"flow update aborted": "Mise à jour du flow annulée",
|
||||
"invalid flow": "Flow invalide",
|
||||
"add schedule": "ajouter récurrence",
|
||||
"schedule": "tâche programmée",
|
||||
"add schedule": "Ajouter un plannificationS",
|
||||
"schedule": "Tâche plannifié",
|
||||
"schedules": {
|
||||
"cron": {
|
||||
"expression": "Expression",
|
||||
"backfilll": "Remblayage",
|
||||
"invalid": "cron expression invalide"
|
||||
}
|
||||
},
|
||||
"inputs": "Entrées",
|
||||
"input": "Entré",
|
||||
"variables": "Variables",
|
||||
"download": "Télécharger"
|
||||
}
|
||||
}
|
||||
|
||||
22
ui/src/utils/flow.js
Normal file
22
ui/src/utils/flow.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import permission from "../models/permission";
|
||||
import action from "../models/action";
|
||||
|
||||
export function canSaveFlow(isEdit, user, flow) {
|
||||
return (
|
||||
isEdit && user &&
|
||||
user.isAllowed(permission.FLOW, action.UPDATE, flow.namespace)
|
||||
) || (
|
||||
!isEdit && user &&
|
||||
user.isAllowed(permission.FLOW, action.CREATE, flow.namespace)
|
||||
);
|
||||
}
|
||||
|
||||
export function saveFlow(self, flow) {
|
||||
return self.$store
|
||||
.dispatch("flow/saveFlow", {
|
||||
flow
|
||||
})
|
||||
.then(() => {
|
||||
self.$toast().success({message: self.$t("flow update ok")});
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user