mirror of https://github.com/Fabio286/antares.git
Merge branch 'master' of https://github.com/antares-sql/antares into ts-renderer
This commit is contained in:
commit
e97401e27d
|
@ -165,6 +165,15 @@
|
|||
"contributions": [
|
||||
"translation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "xak666",
|
||||
"name": "xaka_xak",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/38811437?v=4",
|
||||
"profile": "https://github.com/xak666",
|
||||
"contributions": [
|
||||
"translation"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
"MySQL",
|
||||
"PostgreSQL",
|
||||
"SQLite",
|
||||
"Windows"
|
||||
"Windows",
|
||||
"translation"
|
||||
],
|
||||
"svg.preview.background": "transparent"
|
||||
}
|
32
CHANGELOG.md
32
CHANGELOG.md
|
@ -2,6 +2,38 @@
|
|||
|
||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||
|
||||
### [0.5.5](https://github.com/antares-sql/antares/compare/v0.5.4...v0.5.5) (2022-05-24)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* added dropdown animation ([5398964](https://github.com/antares-sql/antares/commit/539896419064db9127f6a72acdbb11af2c4aa60a))
|
||||
* **translation:** russian translation, closes [#266](https://github.com/antares-sql/antares/issues/266) ([9082960](https://github.com/antares-sql/antares/commit/9082960310573a6e4d14bfbe82ed2eb1489f308d))
|
||||
* **UI:** BaseSelect disabled state ([2b436d8](https://github.com/antares-sql/antares/commit/2b436d8613a1e3dff55d73adbddf5d2cd2452f27))
|
||||
* **UI:** BaseSelect in table filters ([a037d0c](https://github.com/antares-sql/antares/commit/a037d0cc0148444e8e6c5b87c79f6ba9c2a6f0fe))
|
||||
* **UI:** BaseSelect option list scrolls automatically using up/down keys ([0043d07](https://github.com/antares-sql/antares/commit/0043d077081fc49724722a5d5a74986d990c539d))
|
||||
* **UI:** BaseSelect small variant ([5582a12](https://github.com/antares-sql/antares/commit/5582a12bbfade75dbcc7f9d71ada7190ed08d3c2))
|
||||
* **UI:** BaseSelect supports disabled options ([f7e04d6](https://github.com/antares-sql/antares/commit/f7e04d633340a53420ce1c434e906c9434620e6e))
|
||||
* **UI:** BaseSelect supports option groups ([1869e6a](https://github.com/antares-sql/antares/commit/1869e6a1482daf9381d9ac2244bf0aeffa758edc))
|
||||
* **UI:** ForeignKeySelect implements BaseSelect component ([302c664](https://github.com/antares-sql/antares/commit/302c66457deeb50facf4735291640fcf48b78f66))
|
||||
* **UI:** initial BaseSelect integration ([22622df](https://github.com/antares-sql/antares/commit/22622df2cfcb71054c6f6110b7ad9d4f635553dc))
|
||||
* **UI:** new BaseSelect component ([745d551](https://github.com/antares-sql/antares/commit/745d551cc9253eae4e39e5d3406ceee051a7d6c1))
|
||||
* **UI:** select tab replace with BaseSelect component ([42bc919](https://github.com/antares-sql/antares/commit/42bc9196ffc2f64b77f9cb42136255fc74815034))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **PostgreSQL:** idle timeout disabled ([a082514](https://github.com/antares-sql/antares/commit/a082514f88040c7e0ffdf4e8357bab45370a4c39))
|
||||
* query tab content disappears reordering or closing other tabs, closes [#261](https://github.com/antares-sql/antares/issues/261) ([c5baf2b](https://github.com/antares-sql/antares/commit/c5baf2b0d379fdd28ee8cb907628bbfca940e2f6))
|
||||
* SSH tunnel connection error with private key, closes [#260](https://github.com/antares-sql/antares/issues/260) ([c826888](https://github.com/antares-sql/antares/commit/c826888b0dd0908958a4f727ddfa642e846269cf))
|
||||
* **UI:** BaseSelect keyboard navigation ([7c45203](https://github.com/antares-sql/antares/commit/7c452036368fa0db6b9cde7c35e60a8e57bfece7))
|
||||
* **UI:** BaseSelect style ([71b0736](https://github.com/antares-sql/antares/commit/71b0736d0ddbd599ab41cde0a6b0823e2bb7da2f))
|
||||
|
||||
|
||||
### Improvements
|
||||
|
||||
* **UI:** max height for query text area increased ([5d5f1da](https://github.com/antares-sql/antares/commit/5d5f1da97b9adfa743197d8fa0bbb6addd565a7a))
|
||||
|
||||
### [0.5.4](https://github.com/antares-sql/antares/compare/v0.5.3...v0.5.4) (2022-05-10)
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, caste, color, religion, or sexual
|
||||
identity and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the overall
|
||||
community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or advances of
|
||||
any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email address,
|
||||
without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders 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, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
fabio286@gmail.com.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series of
|
||||
actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or permanent
|
||||
ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within the
|
||||
community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.1, available at
|
||||
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
|
||||
|
||||
Community Impact Guidelines were inspired by
|
||||
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
|
||||
[https://www.contributor-covenant.org/translations][translations].
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
||||
[Mozilla CoC]: https://github.com/mozilla/diversity
|
||||
[FAQ]: https://www.contributor-covenant.org/faq
|
||||
[translations]: https://www.contributor-covenant.org/translations
|
|
@ -136,6 +136,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
|||
<td align="center"><a href="https://github.com/raliqala"><img src="https://avatars.githubusercontent.com/u/30502407?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Topollo</b></sub></a><br /><a href="https://github.com/antares-sql/antares/commits?author=raliqala" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/SmileYzn"><img src="https://avatars.githubusercontent.com/u/5851851?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Cleverson</b></sub></a><br /><a href="#translation-SmileYzn" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/fredatgithub"><img src="https://avatars.githubusercontent.com/u/6720055?v=4?s=100" width="100px;" alt=""/><br /><sub><b>fred</b></sub></a><br /><a href="#translation-fredatgithub" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/xak666"><img src="https://avatars.githubusercontent.com/u/38811437?v=4?s=100" width="100px;" alt=""/><br /><sub><b>xaka_xak</b></sub></a><br /><a href="#translation-xak666" title="Translation">🌍</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "antares",
|
||||
"productName": "Antares",
|
||||
"version": "0.5.4",
|
||||
"version": "0.5.5",
|
||||
"description": "A modern, fast and productivity driven SQL client with a focus in UX.",
|
||||
"license": "MIT",
|
||||
"repository": "https://github.com/antares-sql/antares.git",
|
||||
|
|
|
@ -0,0 +1,409 @@
|
|||
<template>
|
||||
<div
|
||||
ref="el"
|
||||
class="select"
|
||||
:class="{'select--open': isOpen, 'select--disabled': disabled}"
|
||||
role="combobox"
|
||||
:tabindex="searchable || disabled ? -1 : tabindex"
|
||||
@focus="activate()"
|
||||
@blur="searchable ? false : handleBlurEvent()"
|
||||
@keyup.esc="deactivate()"
|
||||
@keydown.self.down.prevent="moveDown()"
|
||||
@keydown.self.up.prevent="moveUp"
|
||||
>
|
||||
<div class="select__item-text">
|
||||
<input
|
||||
v-if="searchable"
|
||||
ref="searchInput"
|
||||
class="select__search-input"
|
||||
:style="searchInputStyle"
|
||||
type="text"
|
||||
autocomplete="off"
|
||||
spellcheck="false"
|
||||
:tabindex="tabindex"
|
||||
:value="searchText"
|
||||
@input="searchText = $event.target.value"
|
||||
@focus.prevent="!isOpen ? activate() : false"
|
||||
@blur.prevent="handleBlurEvent()"
|
||||
@keyup.esc="deactivate()"
|
||||
@keydown.down.prevent="keyArrows('down')"
|
||||
@keydown.up.prevent="keyArrows('up')"
|
||||
@keypress.enter.prevent.stop.self="select(filteredOptions[hightlightedIndex])"
|
||||
>
|
||||
<span v-if="searchable && !isOpen || !searchable">{{ currentOptionLabel }}</span>
|
||||
</div>
|
||||
<Transition :name="animation">
|
||||
<div
|
||||
v-if="isOpen"
|
||||
ref="optionList"
|
||||
:class="`select__list-wrapper ${dropdownClass ? dropdownClass : '' }`"
|
||||
>
|
||||
<ul class="select__list" @mousedown.prevent>
|
||||
<li
|
||||
v-for="(opt, index) of filteredOptions"
|
||||
:key="opt.id"
|
||||
:ref="(el) => optionRefs[index] = el"
|
||||
:class="{
|
||||
'select__item': true,
|
||||
'select__group': opt.$type === 'group',
|
||||
'select__option--highlight': opt.$type === 'option' && !opt.disabled && index === hightlightedIndex,
|
||||
'select__option--selected': opt.$type === 'option' && isSelected(opt),
|
||||
'select__option--disabled': opt.disabled
|
||||
}"
|
||||
@click.stop="select(opt)"
|
||||
@mousemove.self="hightlightedIndex = index"
|
||||
>
|
||||
<slot
|
||||
name="option"
|
||||
:option="opt"
|
||||
:index="index"
|
||||
>
|
||||
{{ opt.label }}
|
||||
</slot>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, computed, ref, watch, nextTick, onMounted, onUnmounted } from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'BaseSelect',
|
||||
props: {
|
||||
modelValue: {
|
||||
type: [String, Number, Object, Boolean]
|
||||
},
|
||||
value: {
|
||||
type: [String, Number, Object, Boolean]
|
||||
},
|
||||
searchable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
preserveSearch: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
tabindex: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
options: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
optionTrackBy: {
|
||||
type: [String, Function],
|
||||
default: 'value'
|
||||
},
|
||||
optionLabel: {
|
||||
type: [String, Function],
|
||||
default: 'label'
|
||||
},
|
||||
optionDisabled: {
|
||||
type: Function
|
||||
},
|
||||
groupLabel: {
|
||||
type: String
|
||||
},
|
||||
groupValues: {
|
||||
type: String
|
||||
},
|
||||
closeOnSelect: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
animation: {
|
||||
type: String,
|
||||
default: 'fade-slide-down'
|
||||
},
|
||||
dropdownOffsets: {
|
||||
type: Object,
|
||||
default: () => ({ top: 10, left: 0 })
|
||||
},
|
||||
dropdownClass: {
|
||||
type: String
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
emits: ['select', 'open', 'close', 'update:modelValue', 'change', 'blur'],
|
||||
setup (props, { emit }) {
|
||||
const hightlightedIndex = ref(0);
|
||||
const isOpen = ref(false);
|
||||
const internalValue = ref(props.modelValue || props.value);
|
||||
const el = ref(null);
|
||||
const searchInput = ref(null);
|
||||
const optionList = ref(null);
|
||||
const optionRefs = [];
|
||||
const searchText = ref('');
|
||||
|
||||
const getOptionValue = (opt) => _guess('optionTrackBy', opt);
|
||||
const getOptionLabel = (opt) => _guess('optionLabel', opt);
|
||||
const getOptionDisabled = (opt) => _guess('optionDisabled', opt);
|
||||
const _guess = (name, item) => {
|
||||
const prop = props[name];
|
||||
if (typeof prop === 'function')
|
||||
return prop(item);
|
||||
|
||||
return item[prop] || item;
|
||||
};
|
||||
|
||||
const flattenOptions = computed(() => {
|
||||
return [...props.options].reduce((prev, curr) => {
|
||||
if (curr[props.groupValues] && curr[props.groupValues].length) {
|
||||
prev.push({
|
||||
$type: 'group',
|
||||
label: curr[props.groupLabel],
|
||||
id: `group-${curr[props.groupLabel]}`,
|
||||
count: curr[props.groupLabel].length
|
||||
});
|
||||
|
||||
return prev.concat(curr[props.groupValues].map(el => {
|
||||
const value = getOptionValue(el);
|
||||
return {
|
||||
$type: 'option',
|
||||
label: getOptionLabel(el),
|
||||
id: `option-${value}`,
|
||||
disabled: getOptionDisabled(el) === true,
|
||||
value,
|
||||
$data: {
|
||||
...el
|
||||
}
|
||||
};
|
||||
}));
|
||||
}
|
||||
else {
|
||||
const value = getOptionValue(curr);
|
||||
prev.push({
|
||||
$type: 'option',
|
||||
label: getOptionLabel(curr),
|
||||
id: `option-${value}`,
|
||||
disabled: getOptionDisabled(curr) === true,
|
||||
value,
|
||||
$data: {
|
||||
...curr
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return prev;
|
||||
}, []);
|
||||
});
|
||||
|
||||
const filteredOptions = computed(() => {
|
||||
const normalizedSearch = (searchText.value || '').toLowerCase().trim();
|
||||
|
||||
return normalizedSearch
|
||||
? flattenOptions.value.filter(opt => opt.$type === 'group' || opt.label.trim().toLowerCase().indexOf(normalizedSearch) !== -1)
|
||||
: flattenOptions.value;
|
||||
});
|
||||
|
||||
const searchInputStyle = computed(() => {
|
||||
if (props.searchable)
|
||||
// just hide the input and give the ability to receive focus
|
||||
return isOpen.value ? { with: '100%' } : { width: 0, position: 'absolute', padding: 0, margin: 0 };
|
||||
|
||||
return '';
|
||||
});
|
||||
|
||||
watch(filteredOptions, (options) => {
|
||||
if (hightlightedIndex.value >= options.length -1)
|
||||
hightlightedIndex.value = options.length ? options.length -1 : 0;
|
||||
else
|
||||
hightlightedIndex.value = 0;
|
||||
});
|
||||
|
||||
const currentOptionLabel = computed(() =>
|
||||
flattenOptions.value.find(d => d.value === props.modelValue)?.label
|
||||
);
|
||||
|
||||
const select = (opt) => {
|
||||
if (opt.$type === 'group' || opt.disabled) return;
|
||||
|
||||
internalValue.value = opt.value;
|
||||
emit('select', opt);
|
||||
emit('update:modelValue', opt.value);
|
||||
emit('change', opt);
|
||||
|
||||
if (props.closeOnSelect)
|
||||
deactivate();
|
||||
};
|
||||
|
||||
const isSelected = (opt) => {
|
||||
return internalValue.value === opt.value;
|
||||
};
|
||||
|
||||
const activate = () => {
|
||||
if (isOpen.value || props.disabled) return;
|
||||
isOpen.value = true;
|
||||
hightlightedIndex.value = flattenOptions.value.findIndex(el => el.value === internalValue.value) || 0;
|
||||
|
||||
if (props.searchable)
|
||||
searchInput.value.focus();
|
||||
|
||||
else
|
||||
el.value.focus();
|
||||
|
||||
nextTick(() => {
|
||||
adjustListPosition();
|
||||
scrollTo(optionRefs[hightlightedIndex.value]);
|
||||
});
|
||||
|
||||
emit('open');
|
||||
};
|
||||
|
||||
const deactivate = () => {
|
||||
if (!isOpen.value) return;
|
||||
isOpen.value = false;
|
||||
|
||||
if (props.searchable)
|
||||
searchInput.value?.blur();
|
||||
|
||||
else
|
||||
el.value?.blur();
|
||||
|
||||
if (!props.preserveSearch) searchText.value = '';
|
||||
|
||||
emit('close');
|
||||
};
|
||||
|
||||
const adjustListPosition = () => {
|
||||
const element = el.value;
|
||||
let { left, top } = element.getBoundingClientRect();
|
||||
const { left: offsetLeft = 0, top: offsetTop = 0 } = props.dropdownOffsets;
|
||||
top = top + element.clientHeight + offsetTop;
|
||||
const openBottom = top >= 0 && top + optionList.value.clientHeight <= window.innerHeight;
|
||||
|
||||
if (!openBottom) {
|
||||
top -= (offsetTop * 2 + element.clientHeight);
|
||||
optionList.value.style.transform = 'translate(0, -100%)';
|
||||
}
|
||||
|
||||
optionList.value.style.left = `${left + offsetLeft}px`;
|
||||
optionList.value.style.top = `${top}px`;
|
||||
optionList.value.style.minWidth = `${element.clientWidth}px`;
|
||||
};
|
||||
|
||||
const keyArrows = (direction) => {
|
||||
const sum = direction === 'down' ? +1 : -1;
|
||||
let index = hightlightedIndex.value + sum;
|
||||
index = Math.max(0, index > filteredOptions.value.length - 1 ? filteredOptions.value.length - 1 : index);
|
||||
if (filteredOptions.value[index].$type === 'group')
|
||||
index=Math.max(1, index+sum);
|
||||
|
||||
hightlightedIndex.value = index;
|
||||
|
||||
const optEl = optionRefs[hightlightedIndex.value];
|
||||
if (!optEl)
|
||||
return;
|
||||
|
||||
scrollTo(optEl);
|
||||
};
|
||||
|
||||
const scrollTo = (optEl) => {
|
||||
if (!optEl) return;
|
||||
const visMin = optionList.value.scrollTop;
|
||||
const visMax = optionList.value.scrollTop + optionList.value.clientHeight - optEl.clientHeight;
|
||||
|
||||
if (optEl.offsetTop < visMin)
|
||||
optionList.value.scrollTop = optEl.offsetTop;
|
||||
|
||||
else if (optEl.offsetTop >= visMax)
|
||||
optionList.value.scrollTop = optEl.offsetTop - optionList.value.clientHeight + optEl.clientHeight;
|
||||
};
|
||||
|
||||
const handleBlurEvent = () => {
|
||||
deactivate();
|
||||
emit('blur');
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('resize', adjustListPosition);
|
||||
nextTick(() => {
|
||||
// fix position when the component is created and opened at the same time
|
||||
if (isOpen.value) {
|
||||
setTimeout(() => {
|
||||
adjustListPosition();
|
||||
}, 50);
|
||||
}
|
||||
});
|
||||
});
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', adjustListPosition);
|
||||
});
|
||||
|
||||
return {
|
||||
el,
|
||||
searchInput,
|
||||
searchText,
|
||||
searchInputStyle,
|
||||
filteredOptions,
|
||||
currentOptionLabel,
|
||||
activate,
|
||||
deactivate,
|
||||
select,
|
||||
isSelected,
|
||||
keyArrows,
|
||||
isOpen,
|
||||
hightlightedIndex,
|
||||
optionList,
|
||||
optionRefs,
|
||||
handleBlurEvent
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.select {
|
||||
display: block;
|
||||
|
||||
&:focus, &--open {
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
&__search-input {
|
||||
appearance: none;
|
||||
border: none;
|
||||
background: transparent;
|
||||
outline: none;
|
||||
color: currentColor;
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&__list-wrapper {
|
||||
cursor: pointer;
|
||||
position: fixed;
|
||||
display: block;
|
||||
z-index: 5;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
max-height: 240px;
|
||||
overflow: auto;
|
||||
left: 0;
|
||||
top: 40px;
|
||||
}
|
||||
|
||||
&__list {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
&__option {
|
||||
&--disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
&--disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,38 +1,26 @@
|
|||
<template>
|
||||
<fieldset class="input-group mb-0">
|
||||
<select
|
||||
<BaseSelect
|
||||
v-model="selectedGroup"
|
||||
class="form-select"
|
||||
:options="[{name: 'manual'}, ...fakerGroups]"
|
||||
:option-label="(opt: any) => opt.name === 'manual' ? $t('message.manualValue') : $t(`faker.${opt.name}`)"
|
||||
option-track-by="name"
|
||||
:disabled="!isChecked"
|
||||
style="flex-grow: 0;"
|
||||
@change="onChange"
|
||||
>
|
||||
<option value="manual">
|
||||
{{ $t('message.manualValue') }}
|
||||
</option>
|
||||
<option
|
||||
v-for="group in fakerGroups"
|
||||
:key="group.name"
|
||||
:value="group.name"
|
||||
>
|
||||
{{ $t(`faker.${group.name}`) }}
|
||||
</option>
|
||||
</select>
|
||||
<select
|
||||
/>
|
||||
|
||||
<BaseSelect
|
||||
v-if="selectedGroup !== 'manual'"
|
||||
v-model="selectedMethod"
|
||||
:options="fakerMethods"
|
||||
:option-label="(opt: any) => $t(`faker.${opt.name}`)"
|
||||
option-track-by="name"
|
||||
class="form-select"
|
||||
:disabled="!isChecked"
|
||||
@change="onChange"
|
||||
>
|
||||
<option
|
||||
v-for="method in fakerMethods"
|
||||
:key="method.name"
|
||||
:value="method.name"
|
||||
>
|
||||
{{ $t(`faker.${method.name}`) }}
|
||||
</option>
|
||||
</select>
|
||||
/>
|
||||
<ForeignKeySelect
|
||||
v-else-if="foreignKeys.includes(field.name)"
|
||||
ref="formInput"
|
||||
|
@ -66,21 +54,14 @@
|
|||
:type="inputProps().type"
|
||||
:disabled="!isChecked"
|
||||
>
|
||||
<select
|
||||
<BaseSelect
|
||||
v-else-if="enumArray"
|
||||
v-model="selectedValue"
|
||||
:options="enumArray"
|
||||
class="form-select"
|
||||
:disabled="!isChecked"
|
||||
@change="onChange"
|
||||
>
|
||||
<option
|
||||
v-for="val in enumArray"
|
||||
:key="val"
|
||||
:value="val"
|
||||
>
|
||||
{{ val }}
|
||||
</option>
|
||||
</select>
|
||||
/>
|
||||
<input
|
||||
v-else
|
||||
ref="formInput"
|
||||
|
@ -110,6 +91,7 @@ import { TEXT, LONG_TEXT, NUMBER, FLOAT, DATE, TIME, DATETIME, BLOB, BIT } from
|
|||
import BaseUploadInput from '@/components/BaseUploadInput.vue';
|
||||
import ForeignKeySelect from '@/components/ForeignKeySelect.vue';
|
||||
import FakerMethods from 'common/FakerMethods';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
const props = defineProps({
|
||||
type: String,
|
||||
|
|
|
@ -1,23 +1,15 @@
|
|||
<template>
|
||||
<select
|
||||
<BaseSelect
|
||||
ref="editField"
|
||||
:options="foreigns"
|
||||
class="form-select pl-1 pr-4"
|
||||
:class="{'small-select': size === 'small'}"
|
||||
:value="currentValue"
|
||||
dropdown-class="select-sm"
|
||||
dropdown-container=".workspace-query-results > .vscroll"
|
||||
@change="onChange"
|
||||
@blur="emit('blur')"
|
||||
>
|
||||
<option v-if="!isValidDefault" :value="modelValue">
|
||||
{{ modelValue === null ? 'NULL' : modelValue }}
|
||||
</option>
|
||||
<option
|
||||
v-for="row in foreignList"
|
||||
:key="row.foreign_column"
|
||||
:value="row.foreign_column"
|
||||
:selected="row.foreign_column === modelValue"
|
||||
>
|
||||
{{ row.foreign_column }} {{ cutText('foreign_description' in row ? ` - ${row.foreign_description}` : '') }}
|
||||
</option>
|
||||
</select>
|
||||
@blur="$emit('blur')"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
@ -27,6 +19,7 @@ import Tables from '@/ipc-api/Tables';
|
|||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import { TEXT, LONG_TEXT } from 'common/fieldTypes';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: [String, Number],
|
||||
|
@ -46,6 +39,7 @@ const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
|||
|
||||
const editField: Ref<HTMLSelectElement> = ref(null);
|
||||
const foreignList = ref([]);
|
||||
const currentValue = ref(props.modelValue);
|
||||
|
||||
const isValidDefault = computed(() => {
|
||||
if (!foreignList.value.length) return true;
|
||||
|
@ -53,8 +47,17 @@ const isValidDefault = computed(() => {
|
|||
return foreignList.value.some(foreign => foreign.foreign_column.toString() === props.modelValue.toString());
|
||||
});
|
||||
|
||||
const onChange = () => {
|
||||
emit('update:modelValue', editField.value.value);
|
||||
const foreigns = computed(() => {
|
||||
const list = [];
|
||||
if (!isValidDefault.value)
|
||||
list.push({ value: props.modelValue, label: props.modelValue === null ? 'NULL' : props.modelValue });
|
||||
for (const row of foreignList.value)
|
||||
list.push({ value: row.foreign_column, label: `${row.foreign_column} ${cutText('foreign_description' in row ? ` - ${row.foreign_description}` : '')}` });
|
||||
return list;
|
||||
});
|
||||
|
||||
const onChange = (opt: any) => {
|
||||
emit('update:modelValue', opt.value);
|
||||
};
|
||||
|
||||
const cutText = (val: string) => {
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
</div>
|
||||
<div class="col-9">
|
||||
<input
|
||||
ref="firstInput"
|
||||
v-model="database.name"
|
||||
class="form-input"
|
||||
type="text"
|
||||
|
@ -35,19 +36,13 @@
|
|||
<label class="form-label">{{ $t('word.collation') }}</label>
|
||||
</div>
|
||||
<div class="col-9">
|
||||
<select
|
||||
ref="firstInput"
|
||||
<BaseSelect
|
||||
v-model="database.collation"
|
||||
class="form-select"
|
||||
>
|
||||
<option
|
||||
v-for="collation in collations"
|
||||
:key="collation.id"
|
||||
:value="collation.collation"
|
||||
>
|
||||
{{ collation.collation }}
|
||||
</option>
|
||||
</select>
|
||||
:options="collations"
|
||||
option-label="collation"
|
||||
option-track-by="collation"
|
||||
/>
|
||||
<small>{{ $t('message.serverDefault') }}: {{ defaultCollation }}</small>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -73,6 +68,7 @@ import { storeToRefs } from 'pinia';
|
|||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import Schema from '@/ipc-api/Schema';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
const props = defineProps({
|
||||
selectedSchema: String
|
||||
|
|
|
@ -206,14 +206,11 @@
|
|||
>
|
||||
</div>
|
||||
<div class="column col-6">
|
||||
<select v-model="options.sqlInsertDivider" class="form-select">
|
||||
<option value="bytes">
|
||||
KiB
|
||||
</option>
|
||||
<option value="rows">
|
||||
{{ $tc('word.row', 2) }}
|
||||
</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="options.sqlInsertDivider"
|
||||
class="form-select"
|
||||
:options="[{value: 'bytes', label: 'KiB'}, {value: 'rows', label: $tc('word.row', 2)}]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -223,14 +220,11 @@
|
|||
</div>
|
||||
<div class="columns">
|
||||
<div class="column h5 mb-4">
|
||||
<select v-model="options.outputFormat" class="form-select">
|
||||
<option value="sql">
|
||||
{{ $t('message.singleFile', {ext: '.sql'}) }}
|
||||
</option>
|
||||
<option value="sql.zip">
|
||||
{{ $t('message.zipCompressedFile', {ext: '.sql'}) }}
|
||||
</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="options.outputFormat"
|
||||
class="form-select"
|
||||
:options="[{value: 'sql', label: $t('message.singleFile', {ext: '.sql'})}, {value: 'sql.zip', label: $t('message.zipCompressedFile', {ext: '.sql'})}]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -282,6 +276,7 @@ import { useWorkspacesStore } from '@/stores/workspaces';
|
|||
import Application from '@/ipc-api/Application';
|
||||
import Schema from '@/ipc-api/Schema';
|
||||
import { Customizations } from 'common/interfaces/customizations';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
const props = defineProps({
|
||||
selectedSchema: String
|
||||
|
|
|
@ -72,99 +72,11 @@
|
|||
class="tooltip tooltip-right ml-2"
|
||||
:data-tooltip="$t('message.fakeDataLanguage')"
|
||||
>
|
||||
<select v-model="fakerLocale" class="form-select">
|
||||
<option value="ar">
|
||||
Arabic
|
||||
</option><option value="az">
|
||||
Azerbaijani
|
||||
</option><option value="zh_CN">
|
||||
Chinese
|
||||
</option><option value="zh_TW">
|
||||
Chinese (Taiwan)
|
||||
</option><option value="cz">
|
||||
Czech
|
||||
</option><option value="nl">
|
||||
Dutch
|
||||
</option><option value="nl_BE">
|
||||
Dutch (Belgium)
|
||||
</option><option value="en">
|
||||
English
|
||||
</option><option value="en_AU_ocker">
|
||||
English (Australia Ocker)
|
||||
</option><option value="en_AU">
|
||||
English (Australia)
|
||||
</option><option value="en_BORK">
|
||||
English (Bork)
|
||||
</option><option value="en_CA">
|
||||
English (Canada)
|
||||
</option><option value="en_GB">
|
||||
English (Great Britain)
|
||||
</option><option value="en_IND">
|
||||
English (India)
|
||||
</option><option value="en_IE">
|
||||
English (Ireland)
|
||||
</option><option value="en_ZA">
|
||||
English (South Africa)
|
||||
</option><option value="en_US">
|
||||
English (United States)
|
||||
</option><option value="fa">
|
||||
Farsi
|
||||
</option><option value="fi">
|
||||
Finnish
|
||||
</option><option value="fr">
|
||||
French
|
||||
</option><option value="fr_CA">
|
||||
French (Canada)
|
||||
</option><option value="fr_CH">
|
||||
French (Switzerland)
|
||||
</option><option value="ge">
|
||||
Georgian
|
||||
</option><option value="de">
|
||||
German
|
||||
</option><option value="de_AT">
|
||||
German (Austria)
|
||||
</option><option value="de_CH">
|
||||
German (Switzerland)
|
||||
</option><option value="hr">
|
||||
Hrvatski
|
||||
</option><option value="id_ID">
|
||||
Indonesia
|
||||
</option><option value="it">
|
||||
Italian
|
||||
</option><option value="ja">
|
||||
Japanese
|
||||
</option><option value="ko">
|
||||
Korean
|
||||
</option><option value="nep">
|
||||
Nepalese
|
||||
</option><option value="nb_NO">
|
||||
Norwegian
|
||||
</option><option value="pl">
|
||||
Polish
|
||||
</option><option value="pt_BR">
|
||||
Portuguese (Brazil)
|
||||
</option><option value="pt_PT">
|
||||
Portuguese (Portugal)
|
||||
</option><option value="ro">
|
||||
Romanian
|
||||
</option><option value="ru">
|
||||
Russian
|
||||
</option><option value="sk">
|
||||
Slovakian
|
||||
</option><option value="es">
|
||||
Spanish
|
||||
</option><option value="es_MX">
|
||||
Spanish (Mexico)
|
||||
</option><option value="sv">
|
||||
Swedish
|
||||
</option><option value="tr">
|
||||
Turkish
|
||||
</option><option value="uk">
|
||||
Ukrainian
|
||||
</option><option value="vi">
|
||||
Vietnamese
|
||||
</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="fakerLocale"
|
||||
:options="locales"
|
||||
class="form-select"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column col-auto">
|
||||
|
@ -195,6 +107,7 @@ import { useNotificationsStore } from '@/stores/notifications';
|
|||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import Tables from '@/ipc-api/Tables';
|
||||
import FakerSelect from '@/components/FakerSelect.vue';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
const props = defineProps({
|
||||
tabUid: [String, Number],
|
||||
|
@ -222,6 +135,55 @@ const workspace = computed(() => getWorkspace(selectedWorkspace.value));
|
|||
const foreignKeys = computed(() => props.keyUsage.map(key => key.field));
|
||||
const hasFakes = computed(() => Object.keys(localRow.value).some(field => 'group' in localRow.value[field] && localRow.value[field].group !== 'manual'));
|
||||
|
||||
const locales = [
|
||||
{ value: 'ar', label: 'Arabic' },
|
||||
{ value: 'az', label: 'Azerbaijani' },
|
||||
{ value: 'zh_CN', label: 'Chinese' },
|
||||
{ value: 'zh_TW', label: 'Chinese (Taiwan)' },
|
||||
{ value: 'cz', label: 'Czech' },
|
||||
{ value: 'nl', label: 'Dutch' },
|
||||
{ value: 'nl_BE', label: 'Dutch (Belgium)' },
|
||||
{ value: 'en', label: 'English' },
|
||||
{ value: 'en_AU_ocker', label: 'English (Australia Ocker)' },
|
||||
{ value: 'en_AU', label: 'English (Australia)' },
|
||||
{ value: 'en_BORK', label: 'English (Bork)' },
|
||||
{ value: 'en_CA', label: 'English (Canada)' },
|
||||
{ value: 'en_GB', label: 'English (Great Britain)' },
|
||||
{ value: 'en_IND', label: 'English (India)' },
|
||||
{ value: 'en_IE', label: 'English (Ireland)' },
|
||||
{ value: 'en_ZA', label: 'English (South Africa)' },
|
||||
{ value: 'en_US', label: 'English (United States)' },
|
||||
{ value: 'fa', label: 'Farsi' },
|
||||
{ value: 'fi', label: 'Finnish' },
|
||||
{ value: 'fr', label: 'French' },
|
||||
{ value: 'fr_CA', label: 'French (Canada)' },
|
||||
{ value: 'fr_CH', label: 'French (Switzerland)' },
|
||||
{ value: 'ge', label: 'Georgian' },
|
||||
{ value: 'de', label: 'German' },
|
||||
{ value: 'de_AT', label: 'German (Austria)' },
|
||||
{ value: 'de_CH', label: 'German (Switzerland)' },
|
||||
{ value: 'hr', label: 'Hrvatski' },
|
||||
{ value: 'id_ID', label: 'Indonesia' },
|
||||
{ value: 'it', label: 'Italian' },
|
||||
{ value: 'ja', label: 'Japanese' },
|
||||
{ value: 'ko', label: 'Korean' },
|
||||
{ value: 'nep', label: 'Nepalese' },
|
||||
{ value: 'nb_NO', label: 'Norwegian' },
|
||||
{ value: 'pl', label: 'Polish' },
|
||||
{ value: 'pt_BR', label: 'Portuguese (Brazil)' },
|
||||
{ value: 'pt_PT', label: 'Portuguese (Portugal)' },
|
||||
{ value: 'ro', label: 'Romanian' },
|
||||
{ value: 'ru', label: 'Russian' },
|
||||
{ value: 'sk', label: 'Slovakian' },
|
||||
{ value: 'es', label: 'Spanish' },
|
||||
{ value: 'es_MX', label: 'Spanish (Mexico)' },
|
||||
{ value: 'sv', label: 'Swedish' },
|
||||
{ value: 'tr', label: 'Turkish' },
|
||||
{ value: 'uk', label: 'Ukrainian' },
|
||||
{ value: 'vi', label: 'Vietnamese' }
|
||||
|
||||
];
|
||||
|
||||
watch(nInserts, (val) => {
|
||||
if (!val || val < 1)
|
||||
nInserts.value = 1;
|
||||
|
|
|
@ -35,15 +35,13 @@
|
|||
<label class="form-label">{{ $t('word.collation') }}</label>
|
||||
</div>
|
||||
<div class="col-9">
|
||||
<select v-model="database.collation" class="form-select">
|
||||
<option
|
||||
v-for="collation in collations"
|
||||
:key="collation.id"
|
||||
:value="collation.collation"
|
||||
>
|
||||
{{ collation.collation }}
|
||||
</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="database.collation"
|
||||
class="form-select"
|
||||
:options="collations"
|
||||
option-label="collation"
|
||||
option-track-by="collation"
|
||||
/>
|
||||
<small>{{ $t('message.serverDefault') }}: {{ defaultCollation }}</small>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -73,6 +71,7 @@ import { storeToRefs } from 'pinia';
|
|||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import Schema from '@/ipc-api/Schema';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
|
|
@ -69,19 +69,14 @@
|
|||
</label>
|
||||
</div>
|
||||
<div class="col-3 col-sm-12">
|
||||
<select
|
||||
<BaseSelect
|
||||
v-model="localLocale"
|
||||
class="form-select"
|
||||
:options="locales"
|
||||
option-track-by="code"
|
||||
option-label="name"
|
||||
@change="changeLocale(localLocale)"
|
||||
>
|
||||
<option
|
||||
v-for="(locale, key) in locales"
|
||||
:key="key"
|
||||
:value="locale.code"
|
||||
>
|
||||
{{ locale.name }}
|
||||
</option>
|
||||
</select>
|
||||
/>
|
||||
</div>
|
||||
<div class="col-4 col-sm-12 px-2 p-vcentered">
|
||||
<small class="d-block" style="line-height:1.1; font-size:70%;">
|
||||
|
@ -97,18 +92,12 @@
|
|||
</label>
|
||||
</div>
|
||||
<div class="col-3 col-sm-12">
|
||||
<select
|
||||
<BaseSelect
|
||||
v-model="localPageSize"
|
||||
class="form-select"
|
||||
:options="pageSizes"
|
||||
@change="changePageSize(+localPageSize)"
|
||||
>
|
||||
<option
|
||||
v-for="size in pageSizes"
|
||||
:key="size"
|
||||
>
|
||||
{{ size }}
|
||||
</option>
|
||||
</select>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group column col-12 mb-0">
|
||||
|
@ -231,26 +220,16 @@
|
|||
{{ t('message.editorTheme') }}
|
||||
</div>
|
||||
<div class="column col-6 h5 mb-4">
|
||||
<select
|
||||
<BaseSelect
|
||||
v-model="localEditorTheme"
|
||||
class="form-select"
|
||||
:options="editorThemes"
|
||||
option-label="name"
|
||||
option-track-by="code"
|
||||
group-label="group"
|
||||
group-values="themes"
|
||||
@change="changeEditorTheme(localEditorTheme)"
|
||||
>
|
||||
<optgroup
|
||||
v-for="group in editorThemes"
|
||||
:key="group.group"
|
||||
:label="group.group"
|
||||
>
|
||||
<option
|
||||
v-for="theme in group.themes"
|
||||
:key="theme.name"
|
||||
:value="theme.code"
|
||||
:selected="editorTheme === theme.code"
|
||||
>
|
||||
{{ theme.name }}
|
||||
</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
/>
|
||||
</div>
|
||||
<div class="column col-6 mb-4">
|
||||
<div class="btn-group btn-group-block">
|
||||
|
@ -334,6 +313,7 @@ import { localesNames } from '@/i18n/supported-locales';
|
|||
import ModalSettingsUpdate from '@/components/ModalSettingsUpdate.vue';
|
||||
import ModalSettingsChangelog from '@/components/ModalSettingsChangelog.vue';
|
||||
import BaseTextEditor from '@/components/BaseTextEditor.vue';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
import { computed } from '@vue/reactivity';
|
||||
|
||||
const { t, availableLocales } = useI18n();
|
||||
|
|
|
@ -50,19 +50,13 @@
|
|||
<label class="form-label cut-text">{{ $t('word.client') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<select
|
||||
id="connection-client"
|
||||
<BaseSelect
|
||||
v-model="connection.client"
|
||||
:options="clients"
|
||||
option-track-by="slug"
|
||||
option-label="name"
|
||||
class="form-select"
|
||||
>
|
||||
<option
|
||||
v-for="client in clients"
|
||||
:key="client.slug"
|
||||
:value="client.slug"
|
||||
>
|
||||
{{ client.name }}
|
||||
</option>
|
||||
</select>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="connection.client === 'pg'" class="form-group columns">
|
||||
|
@ -404,12 +398,14 @@ import { useNotificationsStore } from '@/stores/notifications';
|
|||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import ModalAskCredentials from '@/components/ModalAskCredentials';
|
||||
import BaseUploadInput from '@/components/BaseUploadInput';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceAddConnectionPanel',
|
||||
components: {
|
||||
ModalAskCredentials,
|
||||
BaseUploadInput
|
||||
BaseUploadInput,
|
||||
BaseSelect
|
||||
},
|
||||
setup () {
|
||||
const { addConnection } = useConnectionsStore();
|
||||
|
|
|
@ -50,15 +50,15 @@
|
|||
<label class="form-label cut-text">{{ $t('word.client') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<select v-model="localConnection.client" class="form-select">
|
||||
<option
|
||||
v-for="client in clients"
|
||||
:key="client.slug"
|
||||
:value="client.slug"
|
||||
>
|
||||
{{ client.name }}
|
||||
</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="localConnection.client"
|
||||
:options="clients"
|
||||
option-track-by="slug"
|
||||
option-label="name"
|
||||
class="form-select"
|
||||
dropdown-container=".workspace .connection-panel-wrapper"
|
||||
:dropdown-offsets="{top: 10}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="connection.client === 'pg'" class="form-group columns">
|
||||
|
@ -401,12 +401,14 @@ import { useWorkspacesStore } from '@/stores/workspaces';
|
|||
import Connection from '@/ipc-api/Connection';
|
||||
import ModalAskCredentials from '@/components/ModalAskCredentials';
|
||||
import BaseUploadInput from '@/components/BaseUploadInput';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceEditConnectionPanel',
|
||||
components: {
|
||||
ModalAskCredentials,
|
||||
BaseUploadInput
|
||||
BaseUploadInput,
|
||||
BaseSelect
|
||||
},
|
||||
props: {
|
||||
connection: Object
|
||||
|
|
|
@ -57,11 +57,11 @@
|
|||
<label class="form-label">
|
||||
{{ $t('word.language') }}
|
||||
</label>
|
||||
<select v-model="localFunction.language" class="form-select">
|
||||
<option v-for="language in customizations.languages" :key="language">
|
||||
{{ language }}
|
||||
</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="localFunction.language"
|
||||
:options="customizations.languages"
|
||||
class="form-select"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.definer" class="column col-auto">
|
||||
|
@ -69,27 +69,13 @@
|
|||
<label class="form-label">
|
||||
{{ $t('word.definer') }}
|
||||
</label>
|
||||
<select
|
||||
v-if="workspace.users.length"
|
||||
<BaseSelect
|
||||
v-model="localFunction.definer"
|
||||
:options="[{value: '', name:$t('message.currentUser')}, ...workspace.users]"
|
||||
:option-label="(user) => user.value === '' ? user.name : `${user.name}@${user.host}`"
|
||||
:option-track-by="(user) => user.value === '' ? '' : `\`${user.name}\`@\`${user.host}\``"
|
||||
class="form-select"
|
||||
>
|
||||
<option value="">
|
||||
{{ $t('message.currentUser') }}
|
||||
</option>
|
||||
<option
|
||||
v-for="user in workspace.users"
|
||||
:key="`${user.name}@${user.host}`"
|
||||
:value="`\`${user.name}\`@\`${user.host}\``"
|
||||
>
|
||||
{{ user.name }}@{{ user.host }}
|
||||
</option>
|
||||
</select>
|
||||
<select v-if="!workspace.users.length" class="form-select">
|
||||
<option value="">
|
||||
{{ $t('message.currentUser') }}
|
||||
</option>
|
||||
</select>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column col-auto">
|
||||
|
@ -98,29 +84,16 @@
|
|||
{{ $t('word.returns') }}
|
||||
</label>
|
||||
<div class="input-group">
|
||||
<select
|
||||
<BaseSelect
|
||||
v-model="localFunction.returns"
|
||||
class="form-select text-uppercase"
|
||||
:options="[{ name: 'VOID' }, ...workspace.dataTypes]"
|
||||
group-label="group"
|
||||
group-values="types"
|
||||
option-label="name"
|
||||
option-track-by="name"
|
||||
style="max-width: 150px;"
|
||||
>
|
||||
<option v-if="localFunction.returns === 'VOID'">
|
||||
VOID
|
||||
</option>
|
||||
<optgroup
|
||||
v-for="group in workspace.dataTypes"
|
||||
:key="group.group"
|
||||
:label="group.group"
|
||||
>
|
||||
<option
|
||||
v-for="type in group.types"
|
||||
:key="type.name"
|
||||
:selected="localFunction.returns === type.name"
|
||||
:value="type.name"
|
||||
>
|
||||
{{ type.name }}
|
||||
</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
/>
|
||||
<input
|
||||
v-if="customizations.parametersLength"
|
||||
v-model="localFunction.returnsLength"
|
||||
|
@ -150,10 +123,11 @@
|
|||
<label class="form-label">
|
||||
{{ $t('message.sqlSecurity') }}
|
||||
</label>
|
||||
<select v-model="localFunction.security" class="form-select">
|
||||
<option>DEFINER</option>
|
||||
<option>INVOKER</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="localFunction.security"
|
||||
:options="['DEFINER', 'INVOKER']"
|
||||
class="form-select"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.functionDataAccess" class="column col-auto">
|
||||
|
@ -161,12 +135,11 @@
|
|||
<label class="form-label">
|
||||
{{ $t('message.dataAccess') }}
|
||||
</label>
|
||||
<select v-model="localFunction.dataAccess" class="form-select">
|
||||
<option>CONTAINS SQL</option>
|
||||
<option>NO SQL</option>
|
||||
<option>READS SQL DATA</option>
|
||||
<option>MODIFIES SQL DATA</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="localFunction.dataAccess"
|
||||
:options="['CONTAINS SQL', 'NO SQL', 'READS SQL DATA', 'MODIFIES SQL DATA']"
|
||||
class="form-select"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.functionDeterministic" class="column col-auto">
|
||||
|
@ -210,13 +183,15 @@ import QueryEditor from '@/components/QueryEditor';
|
|||
import WorkspaceTabPropsFunctionParamsModal from '@/components/WorkspaceTabPropsFunctionParamsModal';
|
||||
import Functions from '@/ipc-api/Functions';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceTabNewFunction',
|
||||
components: {
|
||||
BaseLoader,
|
||||
QueryEditor,
|
||||
WorkspaceTabPropsFunctionParamsModal
|
||||
WorkspaceTabPropsFunctionParamsModal,
|
||||
BaseSelect
|
||||
},
|
||||
props: {
|
||||
tabUid: String,
|
||||
|
|
|
@ -57,11 +57,11 @@
|
|||
<label class="form-label">
|
||||
{{ $t('word.language') }}
|
||||
</label>
|
||||
<select v-model="localRoutine.language" class="form-select">
|
||||
<option v-for="language in customizations.languages" :key="language">
|
||||
{{ language }}
|
||||
</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="localRoutine.language"
|
||||
:options="customizations.languages"
|
||||
class="form-select"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.definer" class="column col-auto">
|
||||
|
@ -69,27 +69,13 @@
|
|||
<label class="form-label">
|
||||
{{ $t('word.definer') }}
|
||||
</label>
|
||||
<select
|
||||
v-if="workspace.users.length"
|
||||
<BaseSelect
|
||||
v-model="localRoutine.definer"
|
||||
:options="[{value: '', name:$t('message.currentUser')}, ...workspace.users]"
|
||||
:option-label="(user) => user.value === '' ? user.name : `${user.name}@${user.host}`"
|
||||
:option-track-by="(user) => user.value === '' ? '' : `\`${user.name}\`@\`${user.host}\``"
|
||||
class="form-select"
|
||||
>
|
||||
<option value="">
|
||||
{{ $t('message.currentUser') }}
|
||||
</option>
|
||||
<option
|
||||
v-for="user in workspace.users"
|
||||
:key="`${user.name}@${user.host}`"
|
||||
:value="`\`${user.name}\`@\`${user.host}\``"
|
||||
>
|
||||
{{ user.name }}@{{ user.host }}
|
||||
</option>
|
||||
</select>
|
||||
<select v-if="!workspace.users.length" class="form-select">
|
||||
<option value="">
|
||||
{{ $t('message.currentUser') }}
|
||||
</option>
|
||||
</select>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.comment" class="column">
|
||||
|
@ -109,10 +95,11 @@
|
|||
<label class="form-label">
|
||||
{{ $t('message.sqlSecurity') }}
|
||||
</label>
|
||||
<select v-model="localRoutine.security" class="form-select">
|
||||
<option>DEFINER</option>
|
||||
<option>INVOKER</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="localRoutine.security"
|
||||
:options="['DEFINER', 'INVOKER']"
|
||||
class="form-select"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.procedureDataAccess" class="column col-auto">
|
||||
|
@ -120,12 +107,11 @@
|
|||
<label class="form-label">
|
||||
{{ $t('message.dataAccess') }}
|
||||
</label>
|
||||
<select v-model="localRoutine.dataAccess" class="form-select">
|
||||
<option>CONTAINS SQL</option>
|
||||
<option>NO SQL</option>
|
||||
<option>READS SQL DATA</option>
|
||||
<option>MODIFIES SQL DATA</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="localRoutine.dataAccess"
|
||||
:options="['CONTAINS SQL', 'NO SQL', 'READS SQL DATA', 'MODIFIES SQL DATA']"
|
||||
class="form-select"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.procedureDeterministic" class="column col-auto">
|
||||
|
@ -170,13 +156,15 @@ import BaseLoader from '@/components/BaseLoader';
|
|||
import WorkspaceTabPropsRoutineParamsModal from '@/components/WorkspaceTabPropsRoutineParamsModal';
|
||||
import Routines from '@/ipc-api/Routines';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceTabNewRoutine',
|
||||
components: {
|
||||
QueryEditor,
|
||||
BaseLoader,
|
||||
WorkspaceTabPropsRoutineParamsModal
|
||||
WorkspaceTabPropsRoutineParamsModal,
|
||||
BaseSelect
|
||||
},
|
||||
props: {
|
||||
tabUid: String,
|
||||
|
|
|
@ -52,30 +52,13 @@
|
|||
<div class="column col-auto">
|
||||
<div class="form-group">
|
||||
<label class="form-label">{{ $t('word.definer') }}</label>
|
||||
<select
|
||||
v-if="workspace.users.length"
|
||||
<BaseSelect
|
||||
v-model="localScheduler.definer"
|
||||
:options="users"
|
||||
:option-label="(user) => user.value === '' ? $t('message.currentUser') : `${user.name}@${user.host}`"
|
||||
:option-track-by="(user) => user.value === '' ? '' : `\`${user.name}\`@\`${user.host}\``"
|
||||
class="form-select"
|
||||
>
|
||||
<option value="">
|
||||
{{ $t('message.currentUser') }}
|
||||
</option>
|
||||
<option v-if="!isDefinerInUsers" :value="originalScheduler.definer">
|
||||
{{ originalScheduler.definer.replaceAll('`', '') }}
|
||||
</option>
|
||||
<option
|
||||
v-for="user in workspace.users"
|
||||
:key="`${user.name}@${user.host}`"
|
||||
:value="`\`${user.name}\`@\`${user.host}\``"
|
||||
>
|
||||
{{ user.name }}@{{ user.host }}
|
||||
</option>
|
||||
</select>
|
||||
<select v-if="!workspace.users.length" class="form-select">
|
||||
<option value="">
|
||||
{{ $t('message.currentUser') }}
|
||||
</option>
|
||||
</select>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
|
@ -149,13 +132,15 @@ import BaseLoader from '@/components/BaseLoader';
|
|||
import QueryEditor from '@/components/QueryEditor';
|
||||
import WorkspaceTabPropsSchedulerTimingModal from '@/components/WorkspaceTabPropsSchedulerTimingModal';
|
||||
import Schedulers from '@/ipc-api/Schedulers';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceTabNewScheduler',
|
||||
components: {
|
||||
BaseLoader,
|
||||
QueryEditor,
|
||||
WorkspaceTabPropsSchedulerTimingModal
|
||||
WorkspaceTabPropsSchedulerTimingModal,
|
||||
BaseSelect
|
||||
},
|
||||
props: {
|
||||
tabUid: String,
|
||||
|
@ -220,6 +205,15 @@ export default {
|
|||
.map(schema => schema.tables);
|
||||
|
||||
return schemaTables.length ? schemaTables[0].filter(table => table.type === 'table') : [];
|
||||
},
|
||||
users () {
|
||||
const users = [{ value: '' }, ...this.workspace.users];
|
||||
if (!this.isDefinerInUsers) {
|
||||
const [name, host] = this.originalScheduler.definer.replaceAll('`', '').split('@');
|
||||
users.unshift({ name, host });
|
||||
}
|
||||
|
||||
return users;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
|
|
@ -88,15 +88,13 @@
|
|||
<label class="form-label">
|
||||
{{ $t('word.collation') }}
|
||||
</label>
|
||||
<select v-model="localOptions.collation" class="form-select">
|
||||
<option
|
||||
v-for="collation in workspace.collations"
|
||||
:key="collation.id"
|
||||
:value="collation.collation"
|
||||
>
|
||||
{{ collation.collation }}
|
||||
</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="localOptions.collation"
|
||||
:options="workspace.collations"
|
||||
option-label="collation"
|
||||
option-track-by="collation"
|
||||
class="form-select"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="workspace.customizations.engines" class="column col-auto">
|
||||
|
@ -104,15 +102,13 @@
|
|||
<label class="form-label">
|
||||
{{ $t('word.engine') }}
|
||||
</label>
|
||||
<select v-model="localOptions.engine" class="form-select">
|
||||
<option
|
||||
v-for="engine in workspace.engines"
|
||||
:key="engine.name"
|
||||
:value="engine.name"
|
||||
>
|
||||
{{ engine.name }}
|
||||
</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="localOptions.engine"
|
||||
class="form-select"
|
||||
:options="workspace.engines"
|
||||
option-label="name"
|
||||
option-track-by="name"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -175,6 +171,7 @@ import WorkspaceTabPropsTableFields from '@/components/WorkspaceTabPropsTableFie
|
|||
import WorkspaceTabPropsTableIndexesModal from '@/components/WorkspaceTabPropsTableIndexesModal';
|
||||
import WorkspaceTabPropsTableForeignModal from '@/components/WorkspaceTabPropsTableForeignModal';
|
||||
import WorkspaceTabNewTableEmptyState from '@/components/WorkspaceTabNewTableEmptyState';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceTabNewTable',
|
||||
|
@ -183,7 +180,8 @@ export default {
|
|||
WorkspaceTabPropsTableFields,
|
||||
WorkspaceTabPropsTableIndexesModal,
|
||||
WorkspaceTabPropsTableForeignModal,
|
||||
WorkspaceTabNewTableEmptyState
|
||||
WorkspaceTabNewTableEmptyState,
|
||||
BaseSelect
|
||||
},
|
||||
props: {
|
||||
tabUid: String,
|
||||
|
@ -247,12 +245,12 @@ export default {
|
|||
},
|
||||
defaultCollation () {
|
||||
if (this.workspace.customizations.collations)
|
||||
return this.getDatabaseVariable(this.selectedWorkspace, 'collation_server').value || '';
|
||||
return this.getDatabaseVariable(this.selectedWorkspace, 'collation_server')?.value || '';
|
||||
return '';
|
||||
},
|
||||
defaultEngine () {
|
||||
if (this.workspace.customizations.engines)
|
||||
return this.workspace.engines.find(engine => engine.isDefault).name;
|
||||
return this.workspace.engines?.find(engine => engine.isDefault)?.name || '';
|
||||
return '';
|
||||
},
|
||||
schemaTables () {
|
||||
|
|
|
@ -46,60 +46,43 @@
|
|||
<div v-if="customizations.definer" class="column col-auto">
|
||||
<div class="form-group">
|
||||
<label class="form-label">{{ $t('word.definer') }}</label>
|
||||
<select
|
||||
v-if="workspace.users.length"
|
||||
<BaseSelect
|
||||
v-model="localTrigger.definer"
|
||||
:options="users"
|
||||
:option-label="(user) => user.value === '' ? $t('message.currentUser') : `${user.name}@${user.host}`"
|
||||
:option-track-by="(user) => user.value === '' ? '' : `\`${user.name}\`@\`${user.host}\``"
|
||||
class="form-select"
|
||||
>
|
||||
<option value="">
|
||||
{{ $t('message.currentUser') }}
|
||||
</option>
|
||||
<option v-if="!isDefinerInUsers" :value="originalTrigger.definer">
|
||||
{{ originalTrigger.definer.replaceAll('`', '') }}
|
||||
</option>
|
||||
<option
|
||||
v-for="user in workspace.users"
|
||||
:key="`${user.name}@${user.host}`"
|
||||
:value="`\`${user.name}\`@\`${user.host}\``"
|
||||
>
|
||||
{{ user.name }}@{{ user.host }}
|
||||
</option>
|
||||
</select>
|
||||
<select v-if="!workspace.users.length" class="form-select">
|
||||
<option value="">
|
||||
{{ $t('message.currentUser') }}
|
||||
</option>
|
||||
</select>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<fieldset class="column columns mb-0" :disabled="customizations.triggerOnlyRename">
|
||||
<div class="column col-auto">
|
||||
<div class="form-group">
|
||||
<label class="form-label">{{ $t('word.table') }}</label>
|
||||
<select v-model="localTrigger.table" class="form-select">
|
||||
<option v-for="table in schemaTables" :key="table.name">
|
||||
{{ table.name }}
|
||||
</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="localTrigger.table"
|
||||
:options="schemaTables"
|
||||
option-label="name"
|
||||
option-track-by="name"
|
||||
class="form-select"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column col-auto">
|
||||
<div class="form-group">
|
||||
<label class="form-label">{{ $t('word.event') }}</label>
|
||||
<div class="input-group">
|
||||
<select v-model="localTrigger.activation" class="form-select">
|
||||
<option>BEFORE</option>
|
||||
<option>AFTER</option>
|
||||
</select>
|
||||
<select
|
||||
<BaseSelect
|
||||
v-model="localTrigger.activation"
|
||||
:options="['BEFORE', 'AFTER']"
|
||||
class="form-select"
|
||||
/>
|
||||
<BaseSelect
|
||||
v-if="!customizations.triggerMultipleEvents"
|
||||
v-model="localTrigger.event"
|
||||
:options="Object.keys(localEvents)"
|
||||
class="form-select"
|
||||
>
|
||||
<option v-for="event in Object.keys(localEvents)" :key="event">
|
||||
{{ event }}
|
||||
</option>
|
||||
</select>
|
||||
/>
|
||||
<div v-if="customizations.triggerMultipleEvents" class="px-4">
|
||||
<label
|
||||
v-for="event in Object.keys(localEvents)"
|
||||
|
@ -138,12 +121,14 @@ import { useWorkspacesStore } from '@/stores/workspaces';
|
|||
import QueryEditor from '@/components/QueryEditor';
|
||||
import BaseLoader from '@/components/BaseLoader';
|
||||
import Triggers from '@/ipc-api/Triggers';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceTabNewTrigger',
|
||||
components: {
|
||||
BaseLoader,
|
||||
QueryEditor
|
||||
QueryEditor,
|
||||
BaseSelect
|
||||
},
|
||||
props: {
|
||||
tabUid: String,
|
||||
|
@ -211,6 +196,15 @@ export default {
|
|||
.map(schema => schema.tables);
|
||||
|
||||
return schemaTables.length ? schemaTables[0].filter(table => table.type === 'table') : [];
|
||||
},
|
||||
users () {
|
||||
const users = [{ value: '' }, ...this.workspace.users];
|
||||
if (!this.isDefinerInUsers) {
|
||||
const [name, host] = this.originalTrigger.definer.replaceAll('`', '').split('@');
|
||||
users.unshift({ name, host });
|
||||
}
|
||||
|
||||
return users;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
|
|
@ -45,11 +45,11 @@
|
|||
<label class="form-label">
|
||||
{{ $t('word.language') }}
|
||||
</label>
|
||||
<select v-model="localFunction.language" class="form-select">
|
||||
<option v-for="language in customizations.triggerFunctionlanguages" :key="language">
|
||||
{{ language }}
|
||||
</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="localFunction.language"
|
||||
:options="customizations.triggerFunctionlanguages"
|
||||
class="form-select"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.definer" class="column col-auto">
|
||||
|
@ -57,27 +57,13 @@
|
|||
<label class="form-label">
|
||||
{{ $t('word.definer') }}
|
||||
</label>
|
||||
<select
|
||||
v-if="workspace.users.length"
|
||||
<BaseSelect
|
||||
v-model="localFunction.definer"
|
||||
:options="workspace.users"
|
||||
:option-label="(user) => user.value === '' ? $t('message.currentUser') : `${user.name}@${user.host}`"
|
||||
:option-track-by="(user) => user.value === '' ? '' : `\`${user.name}\`@\`${user.host}\``"
|
||||
class="form-select"
|
||||
>
|
||||
<option value="">
|
||||
{{ $t('message.currentUser') }}
|
||||
</option>
|
||||
<option
|
||||
v-for="user in workspace.users"
|
||||
:key="`${user.name}@${user.host}`"
|
||||
:value="`\`${user.name}\`@\`${user.host}\``"
|
||||
>
|
||||
{{ user.name }}@{{ user.host }}
|
||||
</option>
|
||||
</select>
|
||||
<select v-if="!workspace.users.length" class="form-select">
|
||||
<option value="">
|
||||
{{ $t('message.currentUser') }}
|
||||
</option>
|
||||
</select>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.comment" class="form-group">
|
||||
|
@ -114,12 +100,14 @@ import { useWorkspacesStore } from '@/stores/workspaces';
|
|||
import BaseLoader from '@/components/BaseLoader';
|
||||
import QueryEditor from '@/components/QueryEditor';
|
||||
import Functions from '@/ipc-api/Functions';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceTabNewTriggerFunction',
|
||||
components: {
|
||||
BaseLoader,
|
||||
QueryEditor
|
||||
QueryEditor,
|
||||
BaseSelect
|
||||
},
|
||||
props: {
|
||||
tabUid: String,
|
||||
|
|
|
@ -46,61 +46,44 @@
|
|||
<div class="column col-auto">
|
||||
<div v-if="workspace.customizations.definer" class="form-group">
|
||||
<label class="form-label">{{ $t('word.definer') }}</label>
|
||||
<select
|
||||
v-if="workspace.users.length"
|
||||
<BaseSelect
|
||||
v-model="localView.definer"
|
||||
:options="users"
|
||||
:option-label="(user) => user.value === '' ? $t('message.currentUser') : `${user.name}@${user.host}`"
|
||||
:option-track-by="(user) => user.value === '' ? '' : `\`${user.name}\`@\`${user.host}\``"
|
||||
class="form-select"
|
||||
>
|
||||
<option value="">
|
||||
{{ $t('message.currentUser') }}
|
||||
</option>
|
||||
<option v-if="!isDefinerInUsers" :value="originalView.definer">
|
||||
{{ originalView.definer.replaceAll('`', '') }}
|
||||
</option>
|
||||
<option
|
||||
v-for="user in workspace.users"
|
||||
:key="`${user.name}@${user.host}`"
|
||||
:value="`\`${user.name}\`@\`${user.host}\``"
|
||||
>
|
||||
{{ user.name }}@{{ user.host }}
|
||||
</option>
|
||||
</select>
|
||||
<select v-if="!workspace.users.length" class="form-select">
|
||||
<option value="">
|
||||
{{ $t('message.currentUser') }}
|
||||
</option>
|
||||
</select>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column col-auto mr-2">
|
||||
<div v-if="workspace.customizations.viewSqlSecurity" class="form-group">
|
||||
<label class="form-label">{{ $t('message.sqlSecurity') }}</label>
|
||||
<select v-model="localView.security" class="form-select">
|
||||
<option>DEFINER</option>
|
||||
<option>INVOKER</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="localView.security"
|
||||
:options="['DEFINER', 'INVOKER']"
|
||||
class="form-select"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column col-auto mr-2">
|
||||
<div v-if="workspace.customizations.viewAlgorithm" class="form-group">
|
||||
<label class="form-label">{{ $t('word.algorithm') }}</label>
|
||||
<select v-model="localView.algorithm" class="form-select">
|
||||
<option>UNDEFINED</option>
|
||||
<option>MERGE</option>
|
||||
<option>TEMPTABLE</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="localView.algorithm"
|
||||
:options="['UNDEFINED', 'MERGE', 'TEMPTABLE']"
|
||||
class="form-select"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="workspace.customizations.viewUpdateOption" class="column col-auto mr-2">
|
||||
<div class="form-group">
|
||||
<label class="form-label">{{ $t('message.updateOption') }}</label>
|
||||
<select v-model="localView.updateOption" class="form-select">
|
||||
<option value="">
|
||||
None
|
||||
</option>
|
||||
<option>CASCADED</option>
|
||||
<option>LOCAL</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="localView.updateOption"
|
||||
:option-track-by="(user) => user.value"
|
||||
:options="[{label: 'None', value: ''}, {label: 'CASCADED', value: 'CASCADED'}, {label: 'LOCAL', value: 'LOCAL'}]"
|
||||
class="form-select"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -127,12 +110,14 @@ import { useWorkspacesStore } from '@/stores/workspaces';
|
|||
import BaseLoader from '@/components/BaseLoader';
|
||||
import QueryEditor from '@/components/QueryEditor';
|
||||
import Views from '@/ipc-api/Views';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceTabNewView',
|
||||
components: {
|
||||
BaseLoader,
|
||||
QueryEditor
|
||||
QueryEditor,
|
||||
BaseSelect
|
||||
},
|
||||
props: {
|
||||
tabUid: String,
|
||||
|
@ -189,6 +174,15 @@ export default {
|
|||
},
|
||||
isDefinerInUsers () {
|
||||
return this.originalView ? this.workspace.users.some(user => this.originalView.definer === `\`${user.name}\`@\`${user.host}\``) : true;
|
||||
},
|
||||
users () {
|
||||
const users = [{ value: '' }, ...this.workspace.users];
|
||||
if (!this.isDefinerInUsers) {
|
||||
const [name, host] = this.originalView.definer.replaceAll('`', '').split('@');
|
||||
users.unshift({ name, host });
|
||||
}
|
||||
|
||||
return users;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
|
|
@ -66,11 +66,11 @@
|
|||
<label class="form-label">
|
||||
{{ $t('word.language') }}
|
||||
</label>
|
||||
<select v-model="localFunction.language" class="form-select">
|
||||
<option v-for="language in customizations.languages" :key="language">
|
||||
{{ language }}
|
||||
</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="localFunction.language"
|
||||
:options="customizations.languages"
|
||||
class="form-select"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.definer" class="column col-auto">
|
||||
|
@ -78,27 +78,13 @@
|
|||
<label class="form-label">
|
||||
{{ $t('word.definer') }}
|
||||
</label>
|
||||
<select
|
||||
v-if="workspace.users.length"
|
||||
<BaseSelect
|
||||
v-model="localFunction.definer"
|
||||
:options="[{value: '', name:$t('message.currentUser')}, ...workspace.users]"
|
||||
:option-label="(user) => user.value === '' ? user.name : `${user.name}@${user.host}`"
|
||||
:option-track-by="(user) => user.value === '' ? '' : `\`${user.name}\`@\`${user.host}\``"
|
||||
class="form-select"
|
||||
>
|
||||
<option value="">
|
||||
{{ $t('message.currentUser') }}
|
||||
</option>
|
||||
<option
|
||||
v-for="user in workspace.users"
|
||||
:key="`${user.name}@${user.host}`"
|
||||
:value="`\`${user.name}\`@\`${user.host}\``"
|
||||
>
|
||||
{{ user.name }}@{{ user.host }}
|
||||
</option>
|
||||
</select>
|
||||
<select v-if="!workspace.users.length" class="form-select">
|
||||
<option value="">
|
||||
{{ $t('message.currentUser') }}
|
||||
</option>
|
||||
</select>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column col-auto">
|
||||
|
@ -107,32 +93,16 @@
|
|||
{{ $t('word.returns') }}
|
||||
</label>
|
||||
<div class="input-group">
|
||||
<select
|
||||
<BaseSelect
|
||||
v-model="localFunction.returns"
|
||||
class="form-select text-uppercase"
|
||||
:options="[{ name: 'VOID' }, ...workspace.dataTypes]"
|
||||
group-label="group"
|
||||
group-values="types"
|
||||
option-label="name"
|
||||
option-track-by="name"
|
||||
style="max-width: 150px;"
|
||||
>
|
||||
<option v-if="localFunction.returns === 'VOID'">
|
||||
VOID
|
||||
</option>
|
||||
<option v-if="!isInDataTypes">
|
||||
{{ localFunction.returns }}
|
||||
</option>
|
||||
<optgroup
|
||||
v-for="group in workspace.dataTypes"
|
||||
:key="group.group"
|
||||
:label="group.group"
|
||||
>
|
||||
<option
|
||||
v-for="type in group.types"
|
||||
:key="type.name"
|
||||
:selected="localFunction.returns === type.name"
|
||||
:value="type.name"
|
||||
>
|
||||
{{ type.name }}
|
||||
</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
/>
|
||||
<input
|
||||
v-if="customizations.parametersLength"
|
||||
v-model="localFunction.returnsLength"
|
||||
|
@ -162,10 +132,11 @@
|
|||
<label class="form-label">
|
||||
{{ $t('message.sqlSecurity') }}
|
||||
</label>
|
||||
<select v-model="localFunction.security" class="form-select">
|
||||
<option>DEFINER</option>
|
||||
<option>INVOKER</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="localFunction.security"
|
||||
:options="['DEFINER', 'INVOKER']"
|
||||
class="form-select"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.functionDataAccess" class="column col-auto">
|
||||
|
@ -173,12 +144,11 @@
|
|||
<label class="form-label">
|
||||
{{ $t('message.dataAccess') }}
|
||||
</label>
|
||||
<select v-model="localFunction.dataAccess" class="form-select">
|
||||
<option>CONTAINS SQL</option>
|
||||
<option>NO SQL</option>
|
||||
<option>READS SQL DATA</option>
|
||||
<option>MODIFIES SQL DATA</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="localFunction.dataAccess"
|
||||
:options="['CONTAINS SQL', 'NO SQL', 'READS SQL DATA', 'MODIFIES SQL DATA']"
|
||||
class="form-select"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.functionDeterministic" class="column col-auto">
|
||||
|
@ -231,6 +201,7 @@ import QueryEditor from '@/components/QueryEditor';
|
|||
import WorkspaceTabPropsFunctionParamsModal from '@/components/WorkspaceTabPropsFunctionParamsModal';
|
||||
import ModalAskParameters from '@/components/ModalAskParameters';
|
||||
import Functions from '@/ipc-api/Functions';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceTabPropsFunction',
|
||||
|
@ -238,7 +209,8 @@ export default {
|
|||
BaseLoader,
|
||||
QueryEditor,
|
||||
WorkspaceTabPropsFunctionParamsModal,
|
||||
ModalAskParameters
|
||||
ModalAskParameters,
|
||||
BaseSelect
|
||||
},
|
||||
props: {
|
||||
tabUid: String,
|
||||
|
|
|
@ -89,22 +89,15 @@
|
|||
{{ $t('word.type') }}
|
||||
</label>
|
||||
<div class="column">
|
||||
<select v-model="selectedParamObj.type" class="form-select text-uppercase">
|
||||
<optgroup
|
||||
v-for="group in workspace.dataTypes"
|
||||
:key="group.group"
|
||||
:label="group.group"
|
||||
>
|
||||
<option
|
||||
v-for="type in group.types"
|
||||
:key="type.name"
|
||||
:selected="selectedParamObj.type.toUpperCase() === type.name"
|
||||
:value="type.name"
|
||||
>
|
||||
{{ type.name }}
|
||||
</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="selectedParamObj.type"
|
||||
class="form-select text-uppercase"
|
||||
:options="workspace.dataTypes"
|
||||
group-label="group"
|
||||
group-values="types"
|
||||
option-label="name"
|
||||
option-track-by="name"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.parametersLength" class="form-group">
|
||||
|
@ -174,11 +167,13 @@
|
|||
<script>
|
||||
import { uidGen } from 'common/libs/uidGen';
|
||||
import ConfirmModal from '@/components/BaseConfirmModal';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceTabPropsFunctionParamsModal',
|
||||
components: {
|
||||
ConfirmModal
|
||||
ConfirmModal,
|
||||
BaseSelect
|
||||
},
|
||||
props: {
|
||||
localParameters: {
|
||||
|
|
|
@ -66,11 +66,11 @@
|
|||
<label class="form-label">
|
||||
{{ $t('word.language') }}
|
||||
</label>
|
||||
<select v-model="localRoutine.language" class="form-select">
|
||||
<option v-for="language in customizations.languages" :key="language">
|
||||
{{ language }}
|
||||
</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="localRoutine.language"
|
||||
:options="customizations.languages"
|
||||
class="form-select"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.definer" class="column col-auto">
|
||||
|
@ -78,27 +78,13 @@
|
|||
<label class="form-label">
|
||||
{{ $t('word.definer') }}
|
||||
</label>
|
||||
<select
|
||||
v-if="workspace.users.length"
|
||||
<BaseSelect
|
||||
v-model="localRoutine.definer"
|
||||
:options="[{value: '', name:$t('message.currentUser')}, ...workspace.users]"
|
||||
:option-label="(user) => user.value === '' ? user.name : `${user.name}@${user.host}`"
|
||||
:option-track-by="(user) => user.value === '' ? '' : `\`${user.name}\`@\`${user.host}\``"
|
||||
class="form-select"
|
||||
>
|
||||
<option value="">
|
||||
{{ $t('message.currentUser') }}
|
||||
</option>
|
||||
<option
|
||||
v-for="user in workspace.users"
|
||||
:key="`${user.name}@${user.host}`"
|
||||
:value="`\`${user.name}\`@\`${user.host}\``"
|
||||
>
|
||||
{{ user.name }}@{{ user.host }}
|
||||
</option>
|
||||
</select>
|
||||
<select v-if="!workspace.users.length" class="form-select">
|
||||
<option value="">
|
||||
{{ $t('message.currentUser') }}
|
||||
</option>
|
||||
</select>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.comment" class="column">
|
||||
|
@ -118,10 +104,11 @@
|
|||
<label class="form-label">
|
||||
{{ $t('message.sqlSecurity') }}
|
||||
</label>
|
||||
<select v-model="localRoutine.security" class="form-select">
|
||||
<option>DEFINER</option>
|
||||
<option>INVOKER</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="localRoutine.security"
|
||||
:options="['DEFINER', 'INVOKER']"
|
||||
class="form-select"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.procedureDataAccess" class="column col-auto">
|
||||
|
@ -129,12 +116,11 @@
|
|||
<label class="form-label">
|
||||
{{ $t('message.dataAccess') }}
|
||||
</label>
|
||||
<select v-model="localRoutine.dataAccess" class="form-select">
|
||||
<option>CONTAINS SQL</option>
|
||||
<option>NO SQL</option>
|
||||
<option>READS SQL DATA</option>
|
||||
<option>MODIFIES SQL DATA</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="localRoutine.dataAccess"
|
||||
:options="['CONTAINS SQL', 'NO SQL', 'READS SQL DATA', 'MODIFIES SQL DATA']"
|
||||
class="form-select"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.procedureDeterministic" class="column col-auto">
|
||||
|
@ -187,6 +173,7 @@ import BaseLoader from '@/components/BaseLoader';
|
|||
import WorkspaceTabPropsRoutineParamsModal from '@/components/WorkspaceTabPropsRoutineParamsModal';
|
||||
import ModalAskParameters from '@/components/ModalAskParameters';
|
||||
import Routines from '@/ipc-api/Routines';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceTabPropsRoutine',
|
||||
|
@ -194,7 +181,8 @@ export default {
|
|||
QueryEditor,
|
||||
BaseLoader,
|
||||
WorkspaceTabPropsRoutineParamsModal,
|
||||
ModalAskParameters
|
||||
ModalAskParameters,
|
||||
BaseSelect
|
||||
},
|
||||
props: {
|
||||
tabUid: String,
|
||||
|
|
|
@ -89,22 +89,15 @@
|
|||
{{ $t('word.type') }}
|
||||
</label>
|
||||
<div class="column">
|
||||
<select v-model="selectedParamObj.type" class="form-select text-uppercase">
|
||||
<optgroup
|
||||
v-for="group in workspace.dataTypes"
|
||||
:key="group.group"
|
||||
:label="group.group"
|
||||
>
|
||||
<option
|
||||
v-for="type in group.types"
|
||||
:key="type.name"
|
||||
:selected="selectedParamObj.type.toUpperCase() === type.name"
|
||||
:value="type.name"
|
||||
>
|
||||
{{ type.name }}
|
||||
</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="selectedParamObj.type"
|
||||
class="form-select text-uppercase"
|
||||
:options="workspace.dataTypes"
|
||||
group-label="group"
|
||||
group-values="types"
|
||||
option-label="name"
|
||||
option-track-by="name"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.parametersLength" class="form-group">
|
||||
|
@ -174,11 +167,13 @@
|
|||
<script>
|
||||
import { uidGen } from 'common/libs/uidGen';
|
||||
import ConfirmModal from '@/components/BaseConfirmModal';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceTabPropsRoutineParamsModal',
|
||||
components: {
|
||||
ConfirmModal
|
||||
ConfirmModal,
|
||||
BaseSelect
|
||||
},
|
||||
props: {
|
||||
localParameters: {
|
||||
|
|
|
@ -51,30 +51,13 @@
|
|||
<div class="column col-auto">
|
||||
<div class="form-group">
|
||||
<label class="form-label">{{ $t('word.definer') }}</label>
|
||||
<select
|
||||
v-if="workspace.users.length"
|
||||
<BaseSelect
|
||||
v-model="localScheduler.definer"
|
||||
:options="users"
|
||||
:option-label="(user) => user.value === '' ? $t('message.currentUser') : `${user.name}@${user.host}`"
|
||||
:option-track-by="(user) => user.value === '' ? '' : `\`${user.name}\`@\`${user.host}\``"
|
||||
class="form-select"
|
||||
>
|
||||
<option value="">
|
||||
{{ $t('message.currentUser') }}
|
||||
</option>
|
||||
<option v-if="!isDefinerInUsers" :value="originalScheduler.definer">
|
||||
{{ originalScheduler.definer.replaceAll('`', '') }}
|
||||
</option>
|
||||
<option
|
||||
v-for="user in workspace.users"
|
||||
:key="`${user.name}@${user.host}`"
|
||||
:value="`\`${user.name}\`@\`${user.host}\``"
|
||||
>
|
||||
{{ user.name }}@{{ user.host }}
|
||||
</option>
|
||||
</select>
|
||||
<select v-if="!workspace.users.length" class="form-select">
|
||||
<option value="">
|
||||
{{ $t('message.currentUser') }}
|
||||
</option>
|
||||
</select>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
|
@ -148,13 +131,15 @@ import BaseLoader from '@/components/BaseLoader';
|
|||
import QueryEditor from '@/components/QueryEditor';
|
||||
import WorkspaceTabPropsSchedulerTimingModal from '@/components/WorkspaceTabPropsSchedulerTimingModal';
|
||||
import Schedulers from '@/ipc-api/Schedulers';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceTabPropsScheduler',
|
||||
components: {
|
||||
BaseLoader,
|
||||
QueryEditor,
|
||||
WorkspaceTabPropsSchedulerTimingModal
|
||||
WorkspaceTabPropsSchedulerTimingModal,
|
||||
BaseSelect
|
||||
},
|
||||
props: {
|
||||
tabUid: String,
|
||||
|
@ -217,6 +202,15 @@ export default {
|
|||
.map(schema => schema.tables);
|
||||
|
||||
return schemaTables.length ? schemaTables[0].filter(table => table.type === 'table') : [];
|
||||
},
|
||||
users () {
|
||||
const users = [{ value: '' }, ...this.workspace.users];
|
||||
if (!this.isDefinerInUsers) {
|
||||
const [name, host] = this.originalScheduler.definer.replaceAll('`', '').split('@');
|
||||
users.unshift({ name, host });
|
||||
}
|
||||
|
||||
return users;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
|
|
@ -18,14 +18,11 @@
|
|||
{{ $t('word.execution') }}
|
||||
</label>
|
||||
<div class="column">
|
||||
<select
|
||||
ref="firstInput"
|
||||
<BaseSelect
|
||||
v-model="optionsProxy.execution"
|
||||
:options="['EVERY', 'ONCE']"
|
||||
class="form-select"
|
||||
>
|
||||
<option>EVERY</option>
|
||||
<option>ONCE</option>
|
||||
</select>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="optionsProxy.execution === 'EVERY'">
|
||||
|
@ -39,27 +36,26 @@
|
|||
type="text"
|
||||
@keypress="isNumberOrMinus($event)"
|
||||
>
|
||||
<select
|
||||
<BaseSelect
|
||||
v-model="optionsProxy.every[1]"
|
||||
class="form-select text-uppercase"
|
||||
:options="['YEAR',
|
||||
'QUARTER',
|
||||
'MONTH',
|
||||
'WEEK',
|
||||
'DAY',
|
||||
'HOUR',
|
||||
'MINUTE',
|
||||
'SECOND',
|
||||
'YEAR_MONTH',
|
||||
'DAY_HOUR',
|
||||
'DAY_MINUTE',
|
||||
'DAY_SECOND',
|
||||
'HOUR_MINUTE',
|
||||
'HOUR_SECOND',
|
||||
'MINUTE_SECOND']"
|
||||
style="width: 0;"
|
||||
>
|
||||
<option>YEAR</option>
|
||||
<option>QUARTER</option>
|
||||
<option>MONTH</option>
|
||||
<option>WEEK</option>
|
||||
<option>DAY</option>
|
||||
<option>HOUR</option>
|
||||
<option>MINUTE</option>
|
||||
<option>SECOND</option>
|
||||
<option>YEAR_MONTH</option>
|
||||
<option>DAY_HOUR</option>
|
||||
<option>DAY_MINUTE</option>
|
||||
<option>DAY_SECOND</option>
|
||||
<option>HOUR_MINUTE</option>
|
||||
<option>HOUR_SECOND</option>
|
||||
<option>MINUTE_SECOND</option>
|
||||
</select>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -140,11 +136,13 @@
|
|||
<script>
|
||||
import moment from 'moment';
|
||||
import ConfirmModal from '@/components/BaseConfirmModal';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceTabPropsSchedulerTimingModal',
|
||||
components: {
|
||||
ConfirmModal
|
||||
ConfirmModal,
|
||||
BaseSelect
|
||||
},
|
||||
props: {
|
||||
localOptions: Object,
|
||||
|
@ -169,10 +167,6 @@ export default {
|
|||
if (!this.optionsProxy.starts) this.optionsProxy.starts = moment().format('YYYY-MM-DD HH:mm:ss');
|
||||
if (!this.optionsProxy.ends) this.optionsProxy.ends = moment().format('YYYY-MM-DD HH:mm:ss');
|
||||
if (!this.optionsProxy.every.length) this.optionsProxy.every = ['1', 'DAY'];
|
||||
|
||||
setTimeout(() => {
|
||||
this.$refs.firstInput.focus();
|
||||
}, 20);
|
||||
},
|
||||
methods: {
|
||||
confirmOptionsChange () {
|
||||
|
|
|
@ -101,15 +101,13 @@
|
|||
<label class="form-label">
|
||||
{{ $t('word.collation') }}
|
||||
</label>
|
||||
<select v-model="localOptions.collation" class="form-select">
|
||||
<option
|
||||
v-for="collation in workspace.collations"
|
||||
:key="collation.id"
|
||||
:value="collation.collation"
|
||||
>
|
||||
{{ collation.collation }}
|
||||
</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="localOptions.collation"
|
||||
:options="workspace.collations"
|
||||
option-label="collation"
|
||||
option-track-by="collation"
|
||||
class="form-select"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="workspace.customizations.engines" class="column col-auto">
|
||||
|
@ -117,15 +115,13 @@
|
|||
<label class="form-label">
|
||||
{{ $t('word.engine') }}
|
||||
</label>
|
||||
<select v-model="localOptions.engine" class="form-select">
|
||||
<option
|
||||
v-for="engine in workspace.engines"
|
||||
:key="engine.name"
|
||||
:value="engine.name"
|
||||
>
|
||||
{{ engine.name }}
|
||||
</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="localOptions.engine"
|
||||
class="form-select"
|
||||
:options="workspace.engines"
|
||||
option-label="name"
|
||||
option-track-by="name"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -186,6 +182,7 @@ import BaseLoader from '@/components/BaseLoader';
|
|||
import WorkspaceTabPropsTableFields from '@/components/WorkspaceTabPropsTableFields';
|
||||
import WorkspaceTabPropsTableIndexesModal from '@/components/WorkspaceTabPropsTableIndexesModal';
|
||||
import WorkspaceTabPropsTableForeignModal from '@/components/WorkspaceTabPropsTableForeignModal';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceTabPropsTable',
|
||||
|
@ -193,7 +190,8 @@ export default {
|
|||
BaseLoader,
|
||||
WorkspaceTabPropsTableFields,
|
||||
WorkspaceTabPropsTableIndexesModal,
|
||||
WorkspaceTabPropsTableForeignModal
|
||||
WorkspaceTabPropsTableForeignModal,
|
||||
BaseSelect
|
||||
},
|
||||
props: {
|
||||
tabUid: String,
|
||||
|
|
|
@ -117,19 +117,14 @@
|
|||
{{ $t('message.referenceTable') }}
|
||||
</label>
|
||||
<div class="column">
|
||||
<select
|
||||
<BaseSelect
|
||||
v-model="selectedForeignObj.refTable"
|
||||
:options="schemaTables"
|
||||
option-label="name"
|
||||
option-track-by="name"
|
||||
class="form-select"
|
||||
@change="reloadRefFields"
|
||||
>
|
||||
<option
|
||||
v-for="schemaTable in schemaTables"
|
||||
:key="schemaTable.name"
|
||||
:value="schemaTable.name"
|
||||
>
|
||||
{{ schemaTable.name }}
|
||||
</option>
|
||||
</select>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group mb-4">
|
||||
|
@ -153,15 +148,11 @@
|
|||
{{ $t('message.onUpdate') }}
|
||||
</label>
|
||||
<div class="column">
|
||||
<select v-model="selectedForeignObj.onUpdate" class="form-select">
|
||||
<option
|
||||
v-for="action in foreignActions"
|
||||
:key="action"
|
||||
:value="action"
|
||||
>
|
||||
{{ action }}
|
||||
</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="selectedForeignObj.onUpdate"
|
||||
:options="foreignActions"
|
||||
class="form-select"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
|
@ -169,15 +160,11 @@
|
|||
{{ $t('message.onDelete') }}
|
||||
</label>
|
||||
<div class="column">
|
||||
<select v-model="selectedForeignObj.onDelete" class="form-select">
|
||||
<option
|
||||
v-for="action in foreignActions"
|
||||
:key="action"
|
||||
:value="action"
|
||||
>
|
||||
{{ action }}
|
||||
</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="selectedForeignObj.onDelete"
|
||||
:options="foreignActions"
|
||||
class="form-select"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -206,11 +193,13 @@ import { useNotificationsStore } from '@/stores/notifications';
|
|||
import { uidGen } from 'common/libs/uidGen';
|
||||
import Tables from '@/ipc-api/Tables';
|
||||
import ConfirmModal from '@/components/BaseConfirmModal';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceTabPropsTableForeignModal',
|
||||
components: {
|
||||
ConfirmModal
|
||||
ConfirmModal,
|
||||
BaseSelect
|
||||
},
|
||||
props: {
|
||||
localKeyUsage: Array,
|
||||
|
|
|
@ -89,16 +89,12 @@
|
|||
{{ $t('word.type') }}
|
||||
</label>
|
||||
<div class="column">
|
||||
<select v-model="selectedIndexObj.type" class="form-select">
|
||||
<option
|
||||
v-for="index in indexTypes"
|
||||
:key="index"
|
||||
:value="index"
|
||||
:disabled="index === 'PRIMARY' && hasPrimary"
|
||||
>
|
||||
{{ index }}
|
||||
</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="selectedIndexObj.type"
|
||||
:options="indexTypes"
|
||||
:option-disabled="(opt) => opt === 'PRIMARY'"
|
||||
class="form-select"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
|
@ -140,11 +136,13 @@
|
|||
<script>
|
||||
import { uidGen } from 'common/libs/uidGen';
|
||||
import ConfirmModal from '@/components/BaseConfirmModal';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceTabPropsTableIndexesModal',
|
||||
components: {
|
||||
ConfirmModal
|
||||
ConfirmModal,
|
||||
BaseSelect
|
||||
},
|
||||
props: {
|
||||
localIndexes: Array,
|
||||
|
|
|
@ -49,35 +49,22 @@
|
|||
v-if="!isInlineEditor.type"
|
||||
class="cell-content text-left"
|
||||
:class="typeClass(localRow.type)"
|
||||
@click="editON($event, localRow.type.toUpperCase(), 'type')"
|
||||
@dblclick="editON($event, localRow.type.toUpperCase(), 'type')"
|
||||
>
|
||||
{{ localRow.type }}
|
||||
</span>
|
||||
<select
|
||||
<BaseSelect
|
||||
v-else
|
||||
ref="editField"
|
||||
v-model="editingContent"
|
||||
:options="types"
|
||||
group-label="group"
|
||||
group-values="types"
|
||||
option-label="name"
|
||||
option-track-by="name"
|
||||
class="form-select editable-field pl-1 pr-4 small-select text-uppercase"
|
||||
@blur="editOFF"
|
||||
>
|
||||
<option v-if="!isInDataTypes">
|
||||
{{ row.type }}
|
||||
</option>
|
||||
<optgroup
|
||||
v-for="group in dataTypes"
|
||||
:key="group.group"
|
||||
:label="group.group"
|
||||
>
|
||||
<option
|
||||
v-for="type in group.types"
|
||||
:key="type.name"
|
||||
:selected="localRow.type === type.name"
|
||||
:value="type.name"
|
||||
>
|
||||
{{ type.name }}
|
||||
</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="customizations.tableArray"
|
||||
|
@ -214,26 +201,20 @@
|
|||
<span
|
||||
v-if="!isInlineEditor.collation"
|
||||
class="cell-content"
|
||||
@click="editON($event, localRow.collation, 'collation')"
|
||||
@dblclick="editON($event, localRow.collation, 'collation')"
|
||||
>
|
||||
{{ localRow.collation }}
|
||||
</span>
|
||||
<select
|
||||
<BaseSelect
|
||||
v-else
|
||||
ref="editField"
|
||||
v-model="editingContent"
|
||||
:options="collations"
|
||||
option-label="collation"
|
||||
option-track-by="collation"
|
||||
class="form-select small-select pl-1 pr-4 editable-field"
|
||||
@blur="editOFF"
|
||||
>
|
||||
<option
|
||||
v-for="collation in collations"
|
||||
:key="collation.collation"
|
||||
:selected="localRow.collation === collation.collation"
|
||||
:value="collation.collation"
|
||||
>
|
||||
{{ collation.collation }}
|
||||
</option>
|
||||
</select>
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
<ConfirmModal
|
||||
|
@ -347,11 +328,13 @@ import { storeToRefs } from 'pinia';
|
|||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import ConfirmModal from '@/components/BaseConfirmModal';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceTabPropsTableRow',
|
||||
components: {
|
||||
ConfirmModal
|
||||
ConfirmModal,
|
||||
BaseSelect
|
||||
},
|
||||
props: {
|
||||
row: Object,
|
||||
|
@ -431,6 +414,13 @@ export default {
|
|||
typeNames = [...groupTypeNames, ...typeNames];
|
||||
}
|
||||
return typeNames.includes(this.row.type);
|
||||
},
|
||||
types () {
|
||||
const types = [...this.dataTypes];
|
||||
if (!this.isInDataTypes)
|
||||
types.unshift({ name: this.row });
|
||||
|
||||
return types;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
|
|
@ -45,60 +45,44 @@
|
|||
<div v-if="customizations.definer" class="column col-auto">
|
||||
<div class="form-group">
|
||||
<label class="form-label">{{ $t('word.definer') }}</label>
|
||||
<select
|
||||
v-if="workspace.users.length"
|
||||
<BaseSelect
|
||||
v-model="localTrigger.definer"
|
||||
:options="users"
|
||||
:option-label="(user) => user.value === '' ? $t('message.currentUser') : `${user.name}@${user.host}`"
|
||||
:option-track-by="(user) => user.value === '' ? '' : `\`${user.name}\`@\`${user.host}\``"
|
||||
class="form-select"
|
||||
>
|
||||
<option value="">
|
||||
{{ $t('message.currentUser') }}
|
||||
</option>
|
||||
<option v-if="!isDefinerInUsers" :value="originalTrigger.definer">
|
||||
{{ originalTrigger.definer.replaceAll('`', '') }}
|
||||
</option>
|
||||
<option
|
||||
v-for="user in workspace.users"
|
||||
:key="`${user.name}@${user.host}`"
|
||||
:value="`\`${user.name}\`@\`${user.host}\``"
|
||||
>
|
||||
{{ user.name }}@{{ user.host }}
|
||||
</option>
|
||||
</select>
|
||||
<select v-if="!workspace.users.length" class="form-select">
|
||||
<option value="">
|
||||
{{ $t('message.currentUser') }}
|
||||
</option>
|
||||
</select>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<fieldset class="column columns mb-0" :disabled="customizations.triggerOnlyRename">
|
||||
<div class="column col-auto">
|
||||
<div class="form-group">
|
||||
<label class="form-label">{{ $t('word.table') }}</label>
|
||||
<select v-model="localTrigger.table" class="form-select">
|
||||
<option v-for="table in schemaTables" :key="table.name">
|
||||
{{ table.name }}
|
||||
</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="localTrigger.table"
|
||||
:options="schemaTables"
|
||||
option-label="name"
|
||||
option-track-by="name"
|
||||
class="form-select"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column col-auto">
|
||||
<div class="form-group">
|
||||
<label class="form-label">{{ $t('word.event') }}</label>
|
||||
<div class="input-group">
|
||||
<select v-model="localTrigger.activation" class="form-select">
|
||||
<option>BEFORE</option>
|
||||
<option>AFTER</option>
|
||||
</select>
|
||||
<select
|
||||
<BaseSelect
|
||||
v-model="localTrigger.activation"
|
||||
:options="['BEFORE', 'AFTER']"
|
||||
class="form-select"
|
||||
/>
|
||||
<BaseSelect
|
||||
v-if="!customizations.triggerMultipleEvents"
|
||||
v-model="localTrigger.event"
|
||||
:options="Object.keys(localEvents)"
|
||||
class="form-select"
|
||||
>
|
||||
<option v-for="event in Object.keys(localEvents)" :key="event">
|
||||
{{ event }}
|
||||
</option>
|
||||
</select>
|
||||
/>
|
||||
|
||||
<div v-if="customizations.triggerMultipleEvents" class="px-4">
|
||||
<label
|
||||
v-for="event in Object.keys(localEvents)"
|
||||
|
@ -137,12 +121,14 @@ import { useWorkspacesStore } from '@/stores/workspaces';
|
|||
import QueryEditor from '@/components/QueryEditor';
|
||||
import BaseLoader from '@/components/BaseLoader';
|
||||
import Triggers from '@/ipc-api/Triggers';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceTabPropsTrigger',
|
||||
components: {
|
||||
BaseLoader,
|
||||
QueryEditor
|
||||
QueryEditor,
|
||||
BaseSelect
|
||||
},
|
||||
props: {
|
||||
tabUid: String,
|
||||
|
@ -208,6 +194,15 @@ export default {
|
|||
.map(schema => schema.tables);
|
||||
|
||||
return schemaTables.length ? schemaTables[0].filter(table => table.type === 'table') : [];
|
||||
},
|
||||
users () {
|
||||
const users = [{ value: '' }, ...this.workspace.users];
|
||||
if (!this.isDefinerInUsers) {
|
||||
const [name, host] = this.originalTrigger.definer.replaceAll('`', '').split('@');
|
||||
users.unshift({ name, host });
|
||||
}
|
||||
|
||||
return users;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
|
|
@ -32,11 +32,11 @@
|
|||
<label class="form-label">
|
||||
{{ $t('word.language') }}
|
||||
</label>
|
||||
<select v-model="localFunction.language" class="form-select">
|
||||
<option v-for="language in customizations.triggerFunctionlanguages" :key="language">
|
||||
{{ language }}
|
||||
</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="localFunction.language"
|
||||
:options="customizations.triggerFunctionlanguages"
|
||||
class="form-select"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.definer" class="column col-auto">
|
||||
|
@ -44,27 +44,13 @@
|
|||
<label class="form-label">
|
||||
{{ $t('word.definer') }}
|
||||
</label>
|
||||
<select
|
||||
v-if="workspace.users.length"
|
||||
<BaseSelect
|
||||
v-model="localFunction.definer"
|
||||
:options="workspace.users"
|
||||
:option-label="(user) => user.value === '' ? $t('message.currentUser') : `${user.name}@${user.host}`"
|
||||
:option-track-by="(user) => user.value === '' ? '' : `\`${user.name}\`@\`${user.host}\``"
|
||||
class="form-select"
|
||||
>
|
||||
<option value="">
|
||||
{{ $t('message.currentUser') }}
|
||||
</option>
|
||||
<option
|
||||
v-for="user in workspace.users"
|
||||
:key="`${user.name}@${user.host}`"
|
||||
:value="`\`${user.name}\`@\`${user.host}\``"
|
||||
>
|
||||
{{ user.name }}@{{ user.host }}
|
||||
</option>
|
||||
</select>
|
||||
<select v-if="!workspace.users.length" class="form-select">
|
||||
<option value="">
|
||||
{{ $t('message.currentUser') }}
|
||||
</option>
|
||||
</select>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.comment" class="form-group">
|
||||
|
@ -110,13 +96,15 @@ import BaseLoader from '@/components/BaseLoader';
|
|||
import QueryEditor from '@/components/QueryEditor';
|
||||
import ModalAskParameters from '@/components/ModalAskParameters';
|
||||
import Functions from '@/ipc-api/Functions';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceTabPropsTriggerFunction',
|
||||
components: {
|
||||
BaseLoader,
|
||||
QueryEditor,
|
||||
ModalAskParameters
|
||||
ModalAskParameters,
|
||||
BaseSelect
|
||||
},
|
||||
props: {
|
||||
tabUid: String,
|
||||
|
|
|
@ -45,61 +45,44 @@
|
|||
<div class="column col-auto">
|
||||
<div v-if="workspace.customizations.definer" class="form-group">
|
||||
<label class="form-label">{{ $t('word.definer') }}</label>
|
||||
<select
|
||||
v-if="workspace.users.length"
|
||||
<BaseSelect
|
||||
v-model="localView.definer"
|
||||
:options="users"
|
||||
:option-label="(user) => user.value === '' ? $t('message.currentUser') : `${user.name}@${user.host}`"
|
||||
:option-track-by="(user) => user.value === '' ? '' : `\`${user.name}\`@\`${user.host}\``"
|
||||
class="form-select"
|
||||
>
|
||||
<option value="">
|
||||
{{ $t('message.currentUser') }}
|
||||
</option>
|
||||
<option v-if="!isDefinerInUsers" :value="originalView.definer">
|
||||
{{ originalView.definer.replaceAll('`', '') }}
|
||||
</option>
|
||||
<option
|
||||
v-for="user in workspace.users"
|
||||
:key="`${user.name}@${user.host}`"
|
||||
:value="`\`${user.name}\`@\`${user.host}\``"
|
||||
>
|
||||
{{ user.name }}@{{ user.host }}
|
||||
</option>
|
||||
</select>
|
||||
<select v-if="!workspace.users.length" class="form-select">
|
||||
<option value="">
|
||||
{{ $t('message.currentUser') }}
|
||||
</option>
|
||||
</select>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column col-auto mr-2">
|
||||
<div v-if="workspace.customizations.viewSqlSecurity" class="form-group">
|
||||
<label class="form-label">{{ $t('message.sqlSecurity') }}</label>
|
||||
<select v-model="localView.security" class="form-select">
|
||||
<option>DEFINER</option>
|
||||
<option>INVOKER</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="localView.security"
|
||||
:options="['DEFINER', 'INVOKER']"
|
||||
class="form-select"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column col-auto mr-2">
|
||||
<div v-if="workspace.customizations.viewAlgorithm" class="form-group">
|
||||
<label class="form-label">{{ $t('word.algorithm') }}</label>
|
||||
<select v-model="localView.algorithm" class="form-select">
|
||||
<option>UNDEFINED</option>
|
||||
<option>MERGE</option>
|
||||
<option>TEMPTABLE</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="localView.algorithm"
|
||||
:options="['UNDEFINED', 'MERGE', 'TEMPTABLE']"
|
||||
class="form-select"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="workspace.customizations.viewUpdateOption" class="column col-auto mr-2">
|
||||
<div class="form-group">
|
||||
<label class="form-label">{{ $t('message.updateOption') }}</label>
|
||||
<select v-model="localView.updateOption" class="form-select">
|
||||
<option value="">
|
||||
None
|
||||
</option>
|
||||
<option>CASCADED</option>
|
||||
<option>LOCAL</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="localView.updateOption"
|
||||
:option-track-by="(user) => user.value"
|
||||
:options="[{label: 'None', value: ''}, {label: 'CASCADED', value: 'CASCADED'}, {label: 'LOCAL', value: 'LOCAL'}]"
|
||||
class="form-select"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -126,12 +109,14 @@ import { useWorkspacesStore } from '@/stores/workspaces';
|
|||
import BaseLoader from '@/components/BaseLoader';
|
||||
import QueryEditor from '@/components/QueryEditor';
|
||||
import Views from '@/ipc-api/Views';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceTabPropsView',
|
||||
components: {
|
||||
BaseLoader,
|
||||
QueryEditor
|
||||
QueryEditor,
|
||||
BaseSelect
|
||||
},
|
||||
props: {
|
||||
tabUid: String,
|
||||
|
@ -184,6 +169,15 @@ export default {
|
|||
},
|
||||
isDefinerInUsers () {
|
||||
return this.originalView ? this.workspace.users.some(user => this.originalView.definer === `\`${user.name}\`@\`${user.host}\``) : true;
|
||||
},
|
||||
users () {
|
||||
const users = [{ value: '' }, ...this.workspace.users];
|
||||
if (!this.isDefinerInUsers) {
|
||||
const [name, host] = this.originalView.definer.replaceAll('`', '').split('@');
|
||||
users.unshift({ name, host });
|
||||
}
|
||||
|
||||
return users;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
:height="editorHeight"
|
||||
/>
|
||||
<div ref="resizer" class="query-area-resizer" />
|
||||
<div class="workspace-query-runner-footer">
|
||||
<div ref="queryAreaFooter" class="workspace-query-runner-footer">
|
||||
<div class="workspace-query-buttons">
|
||||
<div @mouseenter="setCancelButtonVisibility(true)" @mouseleave="setCancelButtonVisibility(false)">
|
||||
<button
|
||||
|
@ -115,14 +115,13 @@
|
|||
</div>
|
||||
<div class="input-group pr-2" :title="$t('message.commitMode')">
|
||||
<i class="input-group-addon addon-sm mdi mdi-24px mdi-source-commit p-0" />
|
||||
<select v-model="autocommit" class="form-select select-sm text-bold">
|
||||
<option :value="true">
|
||||
{{ $t('message.autoCommit') }}
|
||||
</option>
|
||||
<option :value="false">
|
||||
{{ $t('message.manualCommit') }}
|
||||
</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="autocommit"
|
||||
:options="[{value: true, label: $t('message.autoCommit')}, {value: false, label: $t('message.manualCommit')}]"
|
||||
:option-label="opt => opt.label"
|
||||
:option-track-by="opt => opt.value"
|
||||
class="form-select select-sm text-bold"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="workspace-query-info">
|
||||
|
@ -149,14 +148,12 @@
|
|||
</div>
|
||||
<div class="input-group" :title="$t('word.schema')">
|
||||
<i class="input-group-addon addon-sm mdi mdi-24px mdi-database" />
|
||||
<select v-model="selectedSchema" class="form-select select-sm text-bold">
|
||||
<option :value="null">
|
||||
{{ $t('message.noSchema') }}
|
||||
</option>
|
||||
<option v-for="schemaName in databaseSchemas" :key="schemaName">
|
||||
{{ schemaName }}
|
||||
</option>
|
||||
</select>
|
||||
|
||||
<BaseSelect
|
||||
v-model="selectedSchema"
|
||||
:options="[{value: 'null', label: $t('message.noSchema')}, ...databaseSchemas.map(el => ({label: el, value: el}))]"
|
||||
class="form-select select-sm text-bold"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -199,6 +196,7 @@ import WorkspaceTabQueryTable from '@/components/WorkspaceTabQueryTable';
|
|||
import WorkspaceTabQueryEmptyState from '@/components/WorkspaceTabQueryEmptyState';
|
||||
import ModalHistory from '@/components/ModalHistory';
|
||||
import tableTabs from '@/mixins/tableTabs';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceTabQuery',
|
||||
|
@ -207,7 +205,8 @@ export default {
|
|||
QueryEditor,
|
||||
WorkspaceTabQueryTable,
|
||||
WorkspaceTabQueryEmptyState,
|
||||
ModalHistory
|
||||
ModalHistory,
|
||||
BaseSelect
|
||||
},
|
||||
mixins: [tableTabs],
|
||||
props: {
|
||||
|
@ -320,6 +319,7 @@ export default {
|
|||
this.selectedSchema = null;
|
||||
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
window.addEventListener('resize', this.onWindowResize);
|
||||
},
|
||||
mounted () {
|
||||
const resizer = this.$refs.resizer;
|
||||
|
@ -335,6 +335,7 @@ export default {
|
|||
this.runQuery(this.query);
|
||||
},
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('resize', this.onWindowResize);
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
|
@ -419,11 +420,24 @@ export default {
|
|||
},
|
||||
resize (e) {
|
||||
const el = this.$refs.queryEditor.$el;
|
||||
let editorHeight = e.pageY - el.getBoundingClientRect().top;
|
||||
if (editorHeight > 400) editorHeight = 400;
|
||||
const queryFooterHeight = this.$refs.queryAreaFooter.clientHeight;
|
||||
const bottom = e.pageY || this.$refs.resizer.getBoundingClientRect().bottom;
|
||||
const maxHeight = window.innerHeight - 100 - queryFooterHeight;
|
||||
let editorHeight = bottom - el.getBoundingClientRect().top;
|
||||
if (editorHeight > maxHeight) editorHeight = maxHeight;
|
||||
if (editorHeight < 50) editorHeight = 50;
|
||||
this.editorHeight = editorHeight;
|
||||
},
|
||||
onWindowResize (e) {
|
||||
const el = this.$refs.queryEditor.$el;
|
||||
const queryFooterHeight = this.$refs.queryAreaFooter.clientHeight;
|
||||
const bottom = e.pageY || this.$refs.resizer.getBoundingClientRect().bottom;
|
||||
const maxHeight = window.innerHeight - 100 - queryFooterHeight;
|
||||
const editorHeight = bottom - el.getBoundingClientRect().top;
|
||||
|
||||
if (editorHeight > maxHeight)
|
||||
this.editorHeight = maxHeight;
|
||||
},
|
||||
stopResize () {
|
||||
window.removeEventListener('mousemove', this.resize);
|
||||
if (this.$refs.queryTable && this.results.length)
|
||||
|
@ -520,9 +534,8 @@ export default {
|
|||
position: relative;
|
||||
|
||||
.query-area-resizer {
|
||||
position: absolute;
|
||||
height: 4px;
|
||||
bottom: 40px;
|
||||
margin-top: -2px;
|
||||
width: 100%;
|
||||
cursor: ns-resize;
|
||||
z-index: 99;
|
||||
|
|
|
@ -38,25 +38,21 @@
|
|||
class="editable-field form-input input-sm px-1"
|
||||
@blur="editOFF"
|
||||
>
|
||||
<select
|
||||
<BaseSelect
|
||||
v-else-if="inputProps.type === 'boolean'"
|
||||
v-model="editingContent"
|
||||
:options="['true', 'false']"
|
||||
class="form-select small-select editable-field"
|
||||
@blur="editOFF"
|
||||
>
|
||||
<option>true</option>
|
||||
<option>false</option>
|
||||
</select>
|
||||
<select
|
||||
/>
|
||||
<BaseSelect
|
||||
v-else-if="enumArray"
|
||||
v-model="editingContent"
|
||||
:options="enumArray"
|
||||
class="form-select small-select editable-field"
|
||||
dropdown-class="small-select"
|
||||
@blur="editOFF"
|
||||
>
|
||||
<option v-for="value in enumArray" :key="value">
|
||||
{{ value }}
|
||||
</option>
|
||||
</select>
|
||||
/>
|
||||
<input
|
||||
v-else
|
||||
ref="editField"
|
||||
|
@ -95,19 +91,14 @@
|
|||
<label for="editorMode" class="form-label mr-2">
|
||||
<b>{{ $t('word.content') }}</b>:
|
||||
</label>
|
||||
<select
|
||||
<BaseSelect
|
||||
id="editorMode"
|
||||
v-model="editorMode"
|
||||
:options="availableLanguages"
|
||||
option-label="name"
|
||||
option-track-by="slug"
|
||||
class="form-select select-sm"
|
||||
>
|
||||
<option
|
||||
v-for="language in availableLanguages"
|
||||
:key="language.slug"
|
||||
:value="language.slug"
|
||||
>
|
||||
{{ language.name }}
|
||||
</option>
|
||||
</select>
|
||||
/>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<div class="p-vcentered">
|
||||
|
@ -223,6 +214,7 @@ import ConfirmModal from '@/components/BaseConfirmModal';
|
|||
import TextEditor from '@/components/BaseTextEditor';
|
||||
import BaseMap from '@/components/BaseMap';
|
||||
import ForeignKeySelect from '@/components/ForeignKeySelect';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceTabQueryTableRow',
|
||||
|
@ -230,7 +222,8 @@ export default {
|
|||
ConfirmModal,
|
||||
TextEditor,
|
||||
ForeignKeySelect,
|
||||
BaseMap
|
||||
BaseMap,
|
||||
BaseSelect
|
||||
},
|
||||
props: {
|
||||
row: Object,
|
||||
|
|
|
@ -12,24 +12,18 @@
|
|||
@change="doFilter"
|
||||
><i class="form-icon" />
|
||||
</label>
|
||||
<select v-model="row.field" class="form-select col-auto select-sm">
|
||||
<option
|
||||
v-for="(item, j) of fields"
|
||||
:key="j"
|
||||
:value="item.name"
|
||||
>
|
||||
{{ item.name }}
|
||||
</option>
|
||||
</select>
|
||||
<select v-model="row.op" class="form-select ml-2 col-auto select-sm">
|
||||
<option
|
||||
v-for="(operator, k) of operators"
|
||||
:key="k"
|
||||
:value="operator"
|
||||
>
|
||||
{{ operator }}
|
||||
</option>
|
||||
</select>
|
||||
<BaseSelect
|
||||
v-model="row.field"
|
||||
class="form-select ml-2 col-auto select-sm"
|
||||
:options="fields"
|
||||
option-track-by="name"
|
||||
option-label="name"
|
||||
/>
|
||||
<BaseSelect
|
||||
v-model="row.op"
|
||||
class="form-select ml-2 col-auto select-sm"
|
||||
:options="operators"
|
||||
/>
|
||||
<div class="workspace-table-filters-row-value ml-2">
|
||||
<input
|
||||
v-if="!row.op.includes('NULL')"
|
||||
|
@ -73,8 +67,12 @@
|
|||
<script>
|
||||
import customizations from 'common/customizations';
|
||||
import { NUMBER, FLOAT } from 'common/fieldTypes';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
BaseSelect
|
||||
},
|
||||
props: {
|
||||
fields: Array,
|
||||
connClient: String
|
||||
|
|
|
@ -12,7 +12,8 @@ const i18n = createI18n({
|
|||
'de-DE': require('./de-DE'),
|
||||
'vi-VN': require('./vi-VN'),
|
||||
'ja-JP': require('./ja-JP'),
|
||||
'zh-CN': require('./zh-CN')
|
||||
'zh-CN': require('./zh-CN'),
|
||||
'ru-RU': require('./ru-RU')
|
||||
}
|
||||
});
|
||||
export default i18n;
|
||||
|
|
|
@ -0,0 +1,459 @@
|
|||
module.exports = {
|
||||
word: {
|
||||
edit: 'Редактировать',
|
||||
save: 'Сохранить',
|
||||
close: 'Закрыть',
|
||||
delete: 'Удалить',
|
||||
confirm: 'Подтвердить',
|
||||
cancel: 'Отмена',
|
||||
send: 'Отправить',
|
||||
connectionName: 'Название соединения',
|
||||
client: 'Клиент',
|
||||
hostName: 'Название хоста',
|
||||
port: 'Порт',
|
||||
user: 'Пользователь',
|
||||
password: 'Пароль',
|
||||
credentials: 'Полномочия',
|
||||
connect: 'Подключить',
|
||||
connected: 'Подключено',
|
||||
disconnect: 'Отключить',
|
||||
disconnected: 'Отключено',
|
||||
refresh: 'Обновить',
|
||||
settings: 'Настройка',
|
||||
general: 'Общие',
|
||||
themes: 'Темы',
|
||||
update: 'Обновить',
|
||||
about: 'О программе',
|
||||
language: 'Язык',
|
||||
version: 'Версия',
|
||||
donate: 'Пожертвование',
|
||||
run: 'Запуск',
|
||||
schema: 'Схема',
|
||||
results: 'Результаты',
|
||||
size: 'Размер',
|
||||
seconds: 'Секунды',
|
||||
type: 'Тип',
|
||||
mimeType: 'Mime-Тип',
|
||||
download: 'Скачать',
|
||||
add: 'Добавить',
|
||||
data: 'Данные',
|
||||
properties: 'Свойства',
|
||||
insert: 'Вставить',
|
||||
connecting: 'Соединение',
|
||||
name: 'Название',
|
||||
collation: 'Сопоставление',
|
||||
clear: 'Очистить',
|
||||
options: 'Опции',
|
||||
autoRefresh: 'Авто-обновление',
|
||||
indexes: 'Индексы',
|
||||
foreignKeys: 'Внешние ключи',
|
||||
length: 'Длина',
|
||||
unsigned: 'Неподписанный',
|
||||
default: 'По умолчанию',
|
||||
comment: 'Комментарий',
|
||||
key: 'Ключ | Ключи',
|
||||
order: 'Заказ',
|
||||
expression: 'Выражение',
|
||||
autoIncrement: 'Авто-увеличение',
|
||||
engine: 'Движок',
|
||||
field: 'Поле | Поля',
|
||||
approximately: 'Примерно',
|
||||
total: 'Всего',
|
||||
table: 'Таблица',
|
||||
discard: 'Отказать',
|
||||
stay: 'Оставить',
|
||||
author: 'Автор',
|
||||
light: 'Светлая',
|
||||
dark: 'Темная',
|
||||
autoCompletion: 'Авто-дополнение',
|
||||
application: 'Приложение',
|
||||
editor: 'Реадктор',
|
||||
view: 'Просмотр',
|
||||
definer: 'Определитель',
|
||||
algorithm: 'Алгоритм',
|
||||
trigger: 'Триггер | Триггеры',
|
||||
storedRoutine: 'Сохраненная процедура | Сохраненные процедуры',
|
||||
scheduler: 'Планировщик | Планировщики',
|
||||
event: 'Событие',
|
||||
parameters: 'Параметры',
|
||||
function: 'Функция | Функции',
|
||||
deterministic: 'Детерминированный',
|
||||
context: 'Контекст',
|
||||
export: 'Экспорт',
|
||||
import: 'Импорт',
|
||||
returns: 'Вернуть',
|
||||
timing: 'Сроки',
|
||||
state: 'Состояние',
|
||||
execution: 'Выполнение',
|
||||
starts: 'Начинает',
|
||||
ends: 'Заканчивает',
|
||||
ssl: 'SSL',
|
||||
privateKey: 'Закрытый ключ',
|
||||
certificate: 'Сертификат',
|
||||
caCertificate: 'CA сертификат',
|
||||
ciphers: 'Шифры',
|
||||
upload: 'Загрузки',
|
||||
browse: 'Обзор',
|
||||
faker: 'Faker',
|
||||
content: 'Содержимое',
|
||||
cut: 'Вырезать',
|
||||
copy: 'Копировать',
|
||||
paste: 'Вставить',
|
||||
tools: 'Инструменты',
|
||||
variables: 'Переменные',
|
||||
processes: 'Процессы',
|
||||
database: 'База данных',
|
||||
scratchpad: 'Заметки',
|
||||
array: 'Массив',
|
||||
changelog: 'Журнал изменений',
|
||||
format: 'Формат',
|
||||
sshTunnel: 'SSH туннель',
|
||||
structure: 'Структура',
|
||||
small: 'Малый',
|
||||
medium: 'Средний',
|
||||
large: 'Большой',
|
||||
row: 'Строка | Строки',
|
||||
cell: 'Ячейка | Ячейки',
|
||||
triggerFunction: 'Функция запуска | Функции запуска',
|
||||
all: 'Все',
|
||||
duplicate: 'Дубликат',
|
||||
routine: 'Порядок',
|
||||
new: 'Новый',
|
||||
history: 'История',
|
||||
select: 'Выбрать',
|
||||
passphrase: 'Кодовая фраза',
|
||||
filter: 'Фильтр',
|
||||
change: 'Изменить',
|
||||
views: 'Просмотры',
|
||||
triggers: 'Триггеры',
|
||||
routines: 'Порядок',
|
||||
functions: 'Функции',
|
||||
schedulers: 'Планировщики',
|
||||
includes: 'Включает',
|
||||
drop: 'Сбросить',
|
||||
completed: 'Завершено',
|
||||
aborted: 'Aborted',
|
||||
disabled: 'Прервано',
|
||||
enable: 'Включить',
|
||||
disable: 'Выключить',
|
||||
commit: 'Подтвердить',
|
||||
rollback: 'Отмена',
|
||||
connectionString: 'Строка подключения',
|
||||
contributors: 'Участники'
|
||||
},
|
||||
message: {
|
||||
appWelcome: 'Приветсвуем в SQL клиенте Antares!',
|
||||
appFirstStep: 'Ваш первый шаг: создать новое подключение с БД.',
|
||||
addConnection: 'Добавить подключение',
|
||||
createConnection: 'Создать подключение',
|
||||
createNewConnection: 'Созадть новое подключение',
|
||||
askCredentials: 'Спрашивать учетные данные',
|
||||
testConnection: 'Тестирование подключения',
|
||||
editConnection: 'Редактирование подключения',
|
||||
deleteConnection: 'Удалить подключение',
|
||||
deleteCorfirm: 'Подтверждаете ли вы отмену',
|
||||
connectionSuccessfullyMade: 'Соединение успешно установлено!',
|
||||
madeWithJS: 'Сделано с 💛 и JavaScript!',
|
||||
checkForUpdates: 'Проверить обновления',
|
||||
noUpdatesAvailable: 'Обновлений не найдено',
|
||||
checkingForUpdate: 'Проверить обновления',
|
||||
checkFailure: 'Проверка не удалась, пожалуйста, попробуйте позже',
|
||||
updateAvailable: 'Доступно обновление',
|
||||
downloadingUpdate: 'Скачать обновление',
|
||||
updateDownloaded: 'Обновление скачано',
|
||||
restartToInstall: 'Перезапустить Antares для установки',
|
||||
unableEditFieldWithoutPrimary: 'Невозможно отредактировать поле без первичного ключа в наборе результатов',
|
||||
editCell: 'Редактировать ячейку',
|
||||
deleteRows: 'Удалить строку | Удалить {count} строк',
|
||||
confirmToDeleteRows: 'Подтверждаете удаление строки? | Подтверждаете удаление {count} строк?',
|
||||
notificationsTimeout: 'Тайм-аут уведомлений',
|
||||
uploadFile: 'Загрузить файл',
|
||||
addNewRow: 'Добавить новую строку',
|
||||
numberOfInserts: 'Количество вставок',
|
||||
openNewTab: 'Открыть новую вкладку',
|
||||
affectedRows: 'Задействовано строк',
|
||||
createNewDatabase: 'Создать новую БД',
|
||||
databaseName: 'Название БД',
|
||||
serverDefault: 'Сервер по умолчанию',
|
||||
deleteDatabase: 'Удалить БД',
|
||||
editDatabase: 'Редактировать БД',
|
||||
clearChanges: 'Очистить изменения',
|
||||
addNewField: 'Добавить новое поле',
|
||||
manageIndexes: 'Управление индексами',
|
||||
manageForeignKeys: 'Управление внешними ключами',
|
||||
allowNull: 'Разрешить NULL',
|
||||
zeroFill: 'Заполнить нулями',
|
||||
customValue: 'Пользовательское значение',
|
||||
onUpdate: 'При обновлении',
|
||||
deleteField: 'Удалить поле',
|
||||
createNewIndex: 'Создать новый индекс',
|
||||
addToIndex: 'Добавить индекс',
|
||||
createNewTable: 'Создать новую таблицу',
|
||||
emptyTable: 'Пустая таблица',
|
||||
deleteTable: 'Удалить таблицу',
|
||||
emptyCorfirm: 'Подтверждаете очистку?',
|
||||
unsavedChanges: 'Несохраненные изменения',
|
||||
discardUnsavedChanges: 'У вас имеются несохраненные данные. Закрытие этой вкладки приведёт к их отмене.',
|
||||
thereAreNoIndexes: 'Индексов нет',
|
||||
thereAreNoForeign: 'Внешних ключей нет',
|
||||
createNewForeign: 'Создать новый внешний ключ',
|
||||
referenceTable: 'Ссылка на таблицу',
|
||||
referenceField: 'Ссылка на поле',
|
||||
foreignFields: 'Сторонние поля',
|
||||
invalidDefault: 'Недопустимое значение',
|
||||
onDelete: 'При удалении',
|
||||
applicationTheme: 'Тема приложения',
|
||||
editorTheme: 'Редактировать Тему',
|
||||
wrapLongLines: 'Перенос длинных строк',
|
||||
selectStatement: 'Оператор выбора',
|
||||
triggerStatement: 'Оператор триггера',
|
||||
sqlSecurity: 'SQL безопасность',
|
||||
updateOption: 'Опции обновления',
|
||||
deleteView: 'Удалить просмотр',
|
||||
createNewView: 'Создать новый просмотр',
|
||||
deleteTrigger: 'Удалить триггер',
|
||||
createNewTrigger: 'Создать новый триггер',
|
||||
currentUser: 'Текущий пользователь',
|
||||
routineBody: 'Routine body',
|
||||
dataAccess: 'Доступ к данным',
|
||||
thereAreNoParameters: 'Там нет никаких параметров',
|
||||
createNewParameter: 'Создать новый параметр',
|
||||
createNewRoutine: 'Создание новой сохраненной процедуры',
|
||||
deleteRoutine: 'Удаление сохраненной процедуры',
|
||||
functionBody: 'Тело функции',
|
||||
createNewFunction: 'Создать новую функцию',
|
||||
deleteFunction: 'Удалить функцию',
|
||||
schedulerBody: 'Тело планировщика',
|
||||
createNewScheduler: 'Создать новый планировщик',
|
||||
deleteScheduler: 'Удалить планировщик',
|
||||
preserveOnCompletion: 'Сохранение по завершении',
|
||||
enableSsl: 'Включить SSL',
|
||||
manualValue: 'Установить значение вручную',
|
||||
tableFiller: 'Фильтр таблицы',
|
||||
fakeDataLanguage: 'Язык поддельных данных',
|
||||
searchForElements: 'Поиск элементов',
|
||||
selectAll: 'Выбрать все',
|
||||
queryDuration: 'Длительность запроса',
|
||||
includeBetaUpdates: 'Получать бета-версии обновлений',
|
||||
setNull: 'Установить NULL',
|
||||
processesList: 'Список процессов',
|
||||
processInfo: 'Информация о процессе',
|
||||
manageUsers: 'Управление пользователями',
|
||||
createNewSchema: 'Создать новую схему',
|
||||
schemaName: 'Название схемы',
|
||||
editSchema: 'Редактировать схему',
|
||||
deleteSchema: 'Удалить схему',
|
||||
markdownSupported: 'Поддержка Markdown',
|
||||
plantATree: 'Посадить дерево',
|
||||
dataTabPageSize: 'Размер страницы вкладки ДАННЫЕ',
|
||||
enableSsh: 'Включить SSH',
|
||||
pageNumber: 'Номер страницы',
|
||||
duplicateTable: 'Дубликат таблицы',
|
||||
noOpenTabs: 'Открытых вкладок нет, перейдите по левой панели или:',
|
||||
noSchema: 'Нет схемы',
|
||||
restorePreviourSession: 'Восстановить предыдущую сессию',
|
||||
runQuery: 'Запуск очереди',
|
||||
thereAreNoTableFields: 'В таблице нет полей',
|
||||
newTable: 'Новая таблица',
|
||||
newView: 'Новый просмотр',
|
||||
newTrigger: 'Новый триггер',
|
||||
newRoutine: 'New routine',
|
||||
newFunction: 'Новая функция',
|
||||
newScheduler: 'Новый планировщик',
|
||||
newTriggerFunction: 'Новая функция триггера',
|
||||
thereIsNoQueriesYet: 'Пока нет никаких запросов',
|
||||
searchForQueries: 'Поиск по запросам',
|
||||
killProcess: 'Убить процесс',
|
||||
closeTab: 'Закрыть вкладку',
|
||||
exportSchema: 'Экспорт схемы',
|
||||
importSchema: 'Импорт схемы',
|
||||
directoryPath: 'Путь к каталогу',
|
||||
newInserStmtEvery: 'New INSERT statement every',
|
||||
processingTableExport: 'Обработка {table}',
|
||||
fechingTableExport: 'Получение данных с {table}',
|
||||
writingTableExport: 'Запись данных в {table}',
|
||||
checkAllTables: 'Проверить все таблицы',
|
||||
uncheckAllTables: 'Убрать со всех таблиц',
|
||||
goToDownloadPage: 'Перейти на страницу для загрузки',
|
||||
readOnlyMode: 'Режим только чтение',
|
||||
killQuery: 'Убить запрос',
|
||||
insertRow: 'Вставить строку | Вставить строки',
|
||||
commitMode: 'Режим подтверждения',
|
||||
autoCommit: 'Авто-подтверждение',
|
||||
manualCommit: 'Ручное подтверждение',
|
||||
actionSuccessful: '{action} успешно',
|
||||
importQueryErrors: 'Внимание: {n} ошибка возникла | Внимание: {n} ошибок произошло',
|
||||
executedQueries: '{n} запрос выполнен | {n} запросов выполнено',
|
||||
ourputFormat: 'Формат вывода',
|
||||
singleFile: 'Один {ext} файл',
|
||||
zipCompressedFile: 'ZIP сжатие {ext} файла',
|
||||
disableBlur: 'Отключить размытие',
|
||||
untrustedConnection: 'Ненадежное соединение',
|
||||
missingOrIncompleteTranslation: 'Отсутствующий или неполный перевод?',
|
||||
findOutHowToContribute: 'Узнайте, как внести свой вклад'
|
||||
},
|
||||
faker: {
|
||||
address: 'Адрес',
|
||||
commerce: 'Коммерция',
|
||||
company: 'Компания',
|
||||
database: 'База данных',
|
||||
date: 'Дата',
|
||||
finance: 'Финансы',
|
||||
git: 'Git',
|
||||
hacker: 'Хакер',
|
||||
internet: 'Интернет',
|
||||
lorem: 'Лорем',
|
||||
name: 'Имя',
|
||||
music: 'Музыка',
|
||||
phone: 'Телефон',
|
||||
random: 'Случайный',
|
||||
system: 'Система',
|
||||
time: 'Время',
|
||||
vehicle: 'Vehicle',
|
||||
zipCode: 'Почтовый код',
|
||||
zipCodeByState: 'Почтовый код города',
|
||||
city: 'Город',
|
||||
cityPrefix: 'Префикс города',
|
||||
citySuffix: 'Суфикс города',
|
||||
streetName: 'Название улицы',
|
||||
streetAddress: 'Адрес улицы',
|
||||
streetSuffix: 'Суфикс улицы',
|
||||
streetPrefix: 'Префикс улицы',
|
||||
secondaryAddress: 'Дополнительный адрес',
|
||||
county: 'Округ',
|
||||
country: 'Страна',
|
||||
countryCode: 'Код страны',
|
||||
state: 'Штат',
|
||||
stateAbbr: 'Аббревиатура штата',
|
||||
latitude: 'Широта',
|
||||
longitude: 'Долгота',
|
||||
direction: 'Направление',
|
||||
cardinalDirection: 'Кардинальное направление',
|
||||
ordinalDirection: 'Порядковое направление',
|
||||
nearbyGPSCoordinate: 'Ближайшая GPS-координата',
|
||||
timeZone: 'Часовой пояс',
|
||||
color: 'Цвет',
|
||||
department: 'Отдел',
|
||||
productName: 'Имя продукта',
|
||||
price: 'Прайс',
|
||||
productAdjective: 'Product adjective',
|
||||
productMaterial: 'Product material',
|
||||
product: 'Продукт',
|
||||
productDescription: 'Описание продукта',
|
||||
suffixes: 'Суфиксы',
|
||||
companyName: 'Название компании',
|
||||
companySuffix: 'Суфикс компании',
|
||||
catchPhrase: 'Крылатая фраза',
|
||||
bs: 'BS',
|
||||
catchPhraseAdjective: 'Крылатая фраза прилагательное',
|
||||
catchPhraseDescriptor: 'Дескриптор крылатой фразы',
|
||||
catchPhraseNoun: 'Крылатая фраза существительное',
|
||||
bsAdjective: 'BS прилагательное',
|
||||
bsBuzz: 'BS жужжать',
|
||||
bsNoun: 'BS существительное',
|
||||
column: 'Колонка',
|
||||
type: 'Тип',
|
||||
collation: 'Сопоставление',
|
||||
engine: 'Движок',
|
||||
past: 'Прошлое',
|
||||
future: 'Будущее',
|
||||
between: 'Между',
|
||||
recent: 'Недавнее',
|
||||
soon: 'Вскоре',
|
||||
month: 'Месяц',
|
||||
weekday: 'Будний день',
|
||||
account: 'Аккаунт',
|
||||
accountName: 'Имя аккаунта',
|
||||
routingNumber: 'Routing number',
|
||||
mask: 'Маска',
|
||||
amount: 'Сумма',
|
||||
transactionType: 'Тип транзакции',
|
||||
currencyCode: 'Код валюты',
|
||||
currencyName: 'Название валюты',
|
||||
currencySymbol: 'Символ валюты',
|
||||
bitcoinAddress: 'Bitcoin кошелек',
|
||||
litecoinAddress: 'Litecoin кошелек',
|
||||
creditCardNumber: 'Номер кредитной карты',
|
||||
creditCardCVV: 'CVV код',
|
||||
ethereumAddress: 'Ethereum кошелек',
|
||||
iban: 'Iban',
|
||||
bic: 'Bic',
|
||||
transactionDescription: 'Описание транзакции',
|
||||
branch: 'Ветка',
|
||||
commitEntry: 'Подтвердить запись',
|
||||
commitMessage: 'Подтвердить сообщение',
|
||||
commitSha: 'Подтвердить SHA',
|
||||
shortSha: 'Короткий SHA',
|
||||
abbreviation: 'Сокращение',
|
||||
adjective: 'Прилагательное',
|
||||
noun: 'Существительное',
|
||||
verb: 'Глагол',
|
||||
ingverb: 'Пословица',
|
||||
phrase: 'Фраза',
|
||||
avatar: 'Аватар',
|
||||
email: 'Почта',
|
||||
exampleEmail: 'Пример почты',
|
||||
userName: 'Логин',
|
||||
protocol: 'Протокол',
|
||||
url: 'Url',
|
||||
domainName: 'Название домена',
|
||||
domainSuffix: 'Суфикс домена',
|
||||
domainWord: 'Слово домена',
|
||||
ip: 'Ip',
|
||||
ipv6: 'Ipv6',
|
||||
userAgent: 'User agent',
|
||||
mac: 'Мак-адрес',
|
||||
password: 'Пароль',
|
||||
word: 'Слово',
|
||||
words: 'Слова',
|
||||
sentence: 'Предложение',
|
||||
slug: 'Slug',
|
||||
sentences: 'Sentences',
|
||||
paragraph: 'Параграф',
|
||||
paragraphs: 'Параграфы',
|
||||
text: 'Текст',
|
||||
lines: 'Линии',
|
||||
genre: 'Жанр',
|
||||
firstName: 'Фамилия',
|
||||
lastName: 'Имя',
|
||||
middleName: 'Среднее имя',
|
||||
findName: 'Полное имя',
|
||||
jobTitle: 'Название задания',
|
||||
gender: 'Пол',
|
||||
prefix: 'Префикс',
|
||||
suffix: 'Суфикс',
|
||||
title: 'Заголовок',
|
||||
jobDescriptor: 'Описание задания',
|
||||
jobArea: 'Область задания',
|
||||
jobType: 'Тип задания',
|
||||
phoneNumber: 'Номер телефона',
|
||||
phoneNumberFormat: 'Формат номера',
|
||||
phoneFormats: 'Формат номеров телефона',
|
||||
number: 'Номер',
|
||||
float: 'Дробное число',
|
||||
arrayElement: 'Элемент массива',
|
||||
arrayElements: 'Элементы массива',
|
||||
objectElement: 'Объект элемента',
|
||||
uuid: 'Uuid',
|
||||
boolean: 'Логический',
|
||||
image: 'Изображение',
|
||||
locale: 'Локаль',
|
||||
alpha: 'Альфа',
|
||||
alphaNumeric: 'Буквенно-Цифровой',
|
||||
hexaDecimal: 'Шестнадцатеричный',
|
||||
fileName: 'Имя файла',
|
||||
commonFileName: 'Общее имя файла',
|
||||
mimeType: 'Mime тип',
|
||||
commonFileType: 'Общий тип файло',
|
||||
commonFileExt: 'Общее расширение файлов',
|
||||
fileType: 'Тип файла',
|
||||
fileExt: 'Расширение файла',
|
||||
directoryPath: 'Путь к каталогу',
|
||||
filePath: 'Путь к файлу',
|
||||
semver: 'Semver',
|
||||
manufacturer: 'Производитель',
|
||||
model: 'Модель',
|
||||
fuel: 'Топливо',
|
||||
vin: 'Vin'
|
||||
}
|
||||
};
|
|
@ -8,5 +8,6 @@ export const localesNames: {[key: string]: string} = {
|
|||
'de-DE': 'Deutsch (Deutschland)',
|
||||
'vi-VN': 'Tiếng Việt',
|
||||
'ja-JP': '日本語',
|
||||
'zh-CN': '简体中文'
|
||||
'zh-CN': '简体中文',
|
||||
'ru-RU': 'Русский'
|
||||
};
|
||||
|
|
|
@ -1,3 +1,16 @@
|
|||
.fade-slide-down-enter-active,
|
||||
.fade-slide-down-leave-active {
|
||||
transition: opacity 0.15s ease, transform 0.15s ease;
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.fade-slide-down-enter-from,
|
||||
.fade-slide-down-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateY(-1.8rem);
|
||||
}
|
||||
|
||||
.slide-fade-enter-active {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
|
|
@ -87,7 +87,6 @@ option:checked {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
.workspace-query-results {
|
||||
overflow: auto;
|
||||
white-space: nowrap;
|
||||
|
@ -209,17 +208,17 @@ option:checked {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.modal-overlay{
|
||||
background: rgba( 255, 255, 255, 0.1);
|
||||
box-shadow: 0 8px 32px 0 rgba( 31, 38, 135, 0.37 );
|
||||
|
||||
.modal-overlay {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
|
||||
}
|
||||
}
|
||||
|
||||
#wrapper:not(.no-blur){
|
||||
.modal-overlay{
|
||||
backdrop-filter: blur( 4px );
|
||||
-webkit-backdrop-filter: blur( 4px );
|
||||
#wrapper:not(.no-blur) {
|
||||
.modal-overlay {
|
||||
backdrop-filter: blur(4px);
|
||||
-webkit-backdrop-filter: blur(4px);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -297,6 +296,41 @@ option:checked {
|
|||
font-size: 0.7rem;
|
||||
padding: 1px 0.4rem 0;
|
||||
}
|
||||
|
||||
&.select {
|
||||
&.select--open {
|
||||
border-color: $primary-color !important;
|
||||
@include control-shadow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.select__list {
|
||||
margin: 0;
|
||||
li {
|
||||
margin: 0;
|
||||
padding: 0.3rem 0.8rem;
|
||||
|
||||
.select-sm &,
|
||||
.small-select & {
|
||||
padding: 0.05rem 0.3rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.select__list-wrapper {
|
||||
z-index: 401 !important;
|
||||
border: 1px solid transparent;
|
||||
border-radius: $border-radius;
|
||||
box-shadow: 0px 8px 17px 0px rgba(0, 0, 0, 0.2), 0px 6px 20px 0px rgba(0, 0, 0, 0.19);
|
||||
}
|
||||
|
||||
.select__option--selected {
|
||||
background: rgba($primary-color, 0.25);
|
||||
}
|
||||
|
||||
.select__option--highlight {
|
||||
background: $primary-color;
|
||||
}
|
||||
|
||||
.form-input[type="file"] {
|
||||
|
|
|
@ -121,6 +121,18 @@
|
|||
border-color: $primary-color;
|
||||
}
|
||||
|
||||
.select {
|
||||
&__list-wrapper {
|
||||
border-color: $bg-color-gray;
|
||||
background-color: $bg-color-light-dark;
|
||||
}
|
||||
|
||||
&__group {
|
||||
background: rgba($bg-color-gray, 0.65);
|
||||
color: rgba($bg-color-light-gray, 0.7);
|
||||
}
|
||||
}
|
||||
|
||||
.form-input[readonly] {
|
||||
background-color: $bg-color-dark;
|
||||
cursor: default;
|
||||
|
@ -232,7 +244,7 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.connection-panel {
|
||||
.panel {
|
||||
background: rgba($bg-color-light-dark, 50%);
|
||||
|
@ -240,9 +252,7 @@
|
|||
}
|
||||
|
||||
.bg-checkered {
|
||||
background-image:
|
||||
linear-gradient(to right, rgba(192, 192, 192, 0.75), rgba(192, 192, 192, 0.75)),
|
||||
linear-gradient(to right, black 50%, white 50%),
|
||||
background-image: linear-gradient(to right, rgba(192, 192, 192, 0.75), rgba(192, 192, 192, 0.75)), linear-gradient(to right, black 50%, white 50%),
|
||||
linear-gradient(to bottom, black 50%, white 50%);
|
||||
background-blend-mode: normal, difference, normal;
|
||||
background-size: 2em 2em;
|
||||
|
|
|
@ -18,6 +18,22 @@
|
|||
background: #ababab;
|
||||
}
|
||||
|
||||
.select {
|
||||
&__list-wrapper {
|
||||
border: #bcc3ce;
|
||||
background-color: $body-bg;
|
||||
}
|
||||
|
||||
&__group {
|
||||
background: $bg-color-light-gray;
|
||||
color: $unknown-color;
|
||||
}
|
||||
|
||||
&__option--highlight {
|
||||
color: $light-color;
|
||||
}
|
||||
}
|
||||
|
||||
.menu {
|
||||
.menu-item a {
|
||||
&:hover {
|
||||
|
|
Loading…
Reference in New Issue