Merge branch 'development'
|
|
@ -1,6 +0,0 @@
|
|||
.DS_Store
|
||||
node_modules
|
||||
dist
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
|
@ -29,7 +29,6 @@
|
|||
"vue-router": "^4.2.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@mayank1513/vue-tag-input": "^1.2.0",
|
||||
"@quasar/vite-plugin": "^1.6.0",
|
||||
"@rushstack/eslint-patch": "^1.6.0",
|
||||
"@types/jsdom": "^21.1.6",
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ const props = withDefaults(
|
|||
flat
|
||||
v-close-popup
|
||||
@click="() => ($emit('update:open', !open))"
|
||||
id="dialogDeleteClose"
|
||||
/>
|
||||
|
||||
<q-btn
|
||||
|
|
@ -45,6 +46,7 @@ const props = withDefaults(
|
|||
label="ลบ"
|
||||
class="text-red"
|
||||
@click="() => $emit('confirm')"
|
||||
id="dialogDeleteConfirm"
|
||||
/>
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
<script setup lang="ts">
|
||||
import { onMounted, onUnmounted, ref } from 'vue'
|
||||
|
||||
import { QSelect } from 'quasar'
|
||||
|
||||
const storesCategory: string[] = []
|
||||
const filterDataCategory = ref<string[]>(storesCategory)
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
open: boolean
|
||||
|
|
@ -11,14 +16,17 @@ const props = withDefaults(
|
|||
mode: 'create' | 'edit'
|
||||
title?: string
|
||||
description?: string
|
||||
keyword?: string
|
||||
category?: string
|
||||
keyword?: string[]
|
||||
category?: string[]
|
||||
}>(),
|
||||
{
|
||||
open: false,
|
||||
},
|
||||
)
|
||||
|
||||
const inputKeyword = ref<string[]>(props.keyword || [])
|
||||
const inputCategory = ref<string[]>(props.category || [])
|
||||
|
||||
const emit = defineEmits([
|
||||
'update:open',
|
||||
'update:title',
|
||||
|
|
@ -50,12 +58,41 @@ function submit() {
|
|||
file: file.value,
|
||||
title: props.title ?? '',
|
||||
description: props.description ?? '',
|
||||
keyword: props.keyword ?? '',
|
||||
category: props.category ?? '',
|
||||
keyword: props.keyword,
|
||||
category: props.category,
|
||||
})
|
||||
emit('update:open', !open), reset()
|
||||
}
|
||||
|
||||
const createKeyword = ((val, done) => {
|
||||
if (val.length > 2) {
|
||||
if (!inputKeyword.value.includes(val)) {
|
||||
done(val, 'add-unique')
|
||||
}
|
||||
}
|
||||
}) satisfies QSelect['onNewValue']
|
||||
|
||||
const createCategory = ((val, done) => {
|
||||
if (val.length > 2) {
|
||||
if (!inputCategory.value.includes(val)) {
|
||||
done(val, 'add-unique')
|
||||
}
|
||||
}
|
||||
}) satisfies QSelect['onNewValue']
|
||||
|
||||
const filterCategory = ((val, update) => {
|
||||
update(() => {
|
||||
if (val === '') {
|
||||
filterDataCategory.value = storesCategory
|
||||
} else {
|
||||
const needle = val.toLowerCase()
|
||||
filterDataCategory.value = storesCategory.filter(
|
||||
(v) => v.toLowerCase().indexOf(needle) > -1,
|
||||
)
|
||||
}
|
||||
})
|
||||
}) satisfies QSelect['onFilter']
|
||||
|
||||
onMounted(() => window.addEventListener('keydown', keydown))
|
||||
onUnmounted(() => window.addEventListener('keydown', keydown))
|
||||
|
||||
|
|
@ -92,6 +129,7 @@ const file = ref<File | undefined>()
|
|||
icon="close"
|
||||
color="red"
|
||||
@click="() => ($emit('update:open', !open), reset())"
|
||||
id="fileFormIconClose"
|
||||
/>
|
||||
</q-toolbar>
|
||||
|
||||
|
|
@ -111,6 +149,7 @@ const file = ref<File | undefined>()
|
|||
? 'ไม่สามารถเพิ่มไฟล์ที่ชื่อยาวเกิน 85 ตัวอักษรได้'
|
||||
: ''
|
||||
"
|
||||
id="inputFile"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<q-icon name="attach_file" />
|
||||
|
|
@ -126,7 +165,9 @@ const file = ref<File | undefined>()
|
|||
class="q-my-sm"
|
||||
placeholder="กรอกชื่อเรื่อง"
|
||||
:model-value="title"
|
||||
:rules="[(v) => v.length > 3 || 'ชื่อต้องยาวกว่า 3 ตัวอักษร']"
|
||||
@update:model-value="(v) => $emit('update:title', v)"
|
||||
id="inputTitle"
|
||||
/>
|
||||
</section>
|
||||
|
||||
|
|
@ -140,31 +181,54 @@ const file = ref<File | undefined>()
|
|||
placeholder="กรอกรายละเอียด"
|
||||
:model-value="description"
|
||||
@update:model-value="(v) => $emit('update:description', v)"
|
||||
id="inputDescription"
|
||||
/>
|
||||
</section>
|
||||
|
||||
<section class="q-mb-md">
|
||||
<span class="text-weight-bold">กลุ่ม/หมวดหมู่</span>
|
||||
<q-input
|
||||
outlined
|
||||
dense
|
||||
class="q-mt-sm"
|
||||
placeholder="เลือกกลุ่ม/หมวดหมู่"
|
||||
:model-value="category"
|
||||
@update:model-value="(v) => $emit('update:category', v)"
|
||||
/>
|
||||
<div class="q-mt-md">
|
||||
<q-select
|
||||
outlined
|
||||
:model-value="category"
|
||||
use-input
|
||||
use-chips
|
||||
multiple
|
||||
input-debounce="0"
|
||||
@new-value="createCategory"
|
||||
:options="filterDataCategory"
|
||||
@filter="filterCategory"
|
||||
style="width: 250px"
|
||||
@update:model-value="(v) => $emit('update:category', v)"
|
||||
id="inputCategory"
|
||||
>
|
||||
<template v-slot:no-option>
|
||||
<q-item>
|
||||
<q-item-section class="text-grey"> No results </q-item-section>
|
||||
</q-item>
|
||||
</template>
|
||||
</q-select>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="q-mb-md">
|
||||
<span class="text-weight-bold">คำสำคัญ</span>
|
||||
<q-input
|
||||
outlined
|
||||
dense
|
||||
class="q-mt-sm"
|
||||
placeholder="คำสำคัญ"
|
||||
:model-value="keyword"
|
||||
@update:model-value="(v) => $emit('update:keyword', v)"
|
||||
/>
|
||||
<div class="q-mt-md">
|
||||
<q-select
|
||||
outlined
|
||||
use-input
|
||||
use-chips
|
||||
multiple
|
||||
hide-dropdown-icon
|
||||
input-debounce="0"
|
||||
style="width: 250px"
|
||||
:model-value="props.keyword"
|
||||
@update:model-value="(v) => $emit('update:keyword', v)"
|
||||
@new-value="createKeyword"
|
||||
id="inputKeyword"
|
||||
>
|
||||
</q-select>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section :style="{ display: 'flex', gap: '.5rem' }">
|
||||
|
|
@ -173,6 +237,7 @@ const file = ref<File | undefined>()
|
|||
type="submit"
|
||||
color="primary"
|
||||
:disable="error.fileName2Long"
|
||||
id="submitFile"
|
||||
/>
|
||||
<q-btn
|
||||
label="ยกเลิก"
|
||||
|
|
@ -180,6 +245,7 @@ const file = ref<File | undefined>()
|
|||
color="primary"
|
||||
flat
|
||||
@click="() => ($emit('update:open', false), reset())"
|
||||
id="fileFormBtnClose"
|
||||
/>
|
||||
</section>
|
||||
</q-form>
|
||||
|
|
|
|||
|
|
@ -15,12 +15,13 @@ const props = withDefaults(
|
|||
defineProps<{ action: boolean; viewMode: 'view_list' | 'view_module' }>(),
|
||||
{
|
||||
action: false,
|
||||
},
|
||||
}
|
||||
)
|
||||
const DEPT_NAME = ['ตู้เอกสาร', 'ลิ้นชัก', 'แฟ้ม', 'แฟ้มย่อย'] as const
|
||||
const { getFileInfo, getFileNameFormat } = useFileInfoStore()
|
||||
const { currentFolder, currentFile, currentDept, currentPath } =
|
||||
storeToRefs(useTreeDataStore())
|
||||
const { currentFolder, currentFile, currentDept, currentPath } = storeToRefs(
|
||||
useTreeDataStore()
|
||||
)
|
||||
const {
|
||||
createFolder,
|
||||
editFolder,
|
||||
|
|
@ -30,15 +31,15 @@ const {
|
|||
updateFile,
|
||||
deleteFile,
|
||||
checkFile,
|
||||
checkFileName,
|
||||
refaceFile,
|
||||
} = useTreeDataStore()
|
||||
|
||||
const currentIcon = computed(() =>
|
||||
currentDept.value === 0
|
||||
? 'mdi-file-cabinet'
|
||||
: currentDept.value === 1
|
||||
? 'inbox'
|
||||
: 'o_folder_open',
|
||||
? 'inbox'
|
||||
: 'o_folder_open'
|
||||
)
|
||||
|
||||
const dialogDeleteState = ref<boolean>(false)
|
||||
|
|
@ -57,11 +58,11 @@ const fileFormData = ref<{
|
|||
file?: File
|
||||
title?: string
|
||||
description?: string
|
||||
keyword?: string
|
||||
category?: string
|
||||
keyword?: string[]
|
||||
category?: string[]
|
||||
}>({})
|
||||
const fileFormType = ref<'edit' | 'create'>('create')
|
||||
const fileFormError = ref<{ fileExist?: boolean; fileName2Long?: boolean }>({})
|
||||
const fileFormError = ref<{ fileExist?: boolean }>({})
|
||||
const fileExistNotification = ref<boolean>(false)
|
||||
|
||||
function triggerFolderDelete(pathname: string) {
|
||||
|
|
@ -110,10 +111,10 @@ function triggerFileEdit(
|
|||
value: {
|
||||
title: string
|
||||
description: string
|
||||
keyword: string
|
||||
category: string
|
||||
keyword: string[]
|
||||
category: string[]
|
||||
},
|
||||
pathname: string,
|
||||
pathname: string
|
||||
) {
|
||||
fileFormState.value = true
|
||||
fileFormType.value = 'edit'
|
||||
|
|
@ -122,7 +123,7 @@ function triggerFileEdit(
|
|||
title: value.title,
|
||||
description: value.description,
|
||||
keyword: value.keyword,
|
||||
category: value.keyword,
|
||||
category: value.category,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -134,10 +135,10 @@ async function submitFileForm(
|
|||
file?: File
|
||||
title: string
|
||||
description: string
|
||||
keyword: string
|
||||
category: string
|
||||
keyword: string[]
|
||||
category: string[]
|
||||
},
|
||||
force = false,
|
||||
force = false
|
||||
) {
|
||||
currentParam.value = value
|
||||
|
||||
|
|
@ -153,6 +154,13 @@ async function submitFileForm(
|
|||
keyword: value.keyword,
|
||||
category: value.category,
|
||||
})
|
||||
setTimeout(() => {
|
||||
refaceFile(currentPath.value)
|
||||
}, 3000)
|
||||
|
||||
setTimeout(() => {
|
||||
refaceFile(currentPath.value)
|
||||
}, 10000)
|
||||
} else {
|
||||
await updateFile(
|
||||
fileFormPath.value,
|
||||
|
|
@ -162,7 +170,7 @@ async function submitFileForm(
|
|||
keyword: value.keyword,
|
||||
category: value.category,
|
||||
},
|
||||
value.file,
|
||||
value.file
|
||||
)
|
||||
}
|
||||
fileFormData.value = {}
|
||||
|
|
@ -176,7 +184,8 @@ async function submitFileForm(
|
|||
{{ DEPT_NAME[currentDept] }}
|
||||
</div>
|
||||
<div class="grid q-mt-md">
|
||||
<div v-for="value in currentFolder">
|
||||
<div v-for="value in currentFolder" key="value.name">
|
||||
{{ value.name }}
|
||||
<div
|
||||
:style="{
|
||||
position: 'relative',
|
||||
|
|
@ -187,7 +196,11 @@ async function submitFileForm(
|
|||
padding: currentDept > 2 ? '.5rem 0' : '.5rem',
|
||||
}"
|
||||
class="box"
|
||||
@click="() => getFolder(value.pathname)"
|
||||
@click="
|
||||
() => {
|
||||
;(folderFormState = false), getFolder(value.pathname)
|
||||
}
|
||||
"
|
||||
>
|
||||
<div class="q-px-md flex items-center justify-center">
|
||||
<q-icon
|
||||
|
|
@ -307,10 +320,10 @@ async function submitFileForm(
|
|||
{
|
||||
title: value.title,
|
||||
description: value.description,
|
||||
keyword: value.keyword.join(','),
|
||||
category: value.category.join(','),
|
||||
keyword: value.keyword,
|
||||
category: value.category,
|
||||
},
|
||||
value.pathname,
|
||||
value.pathname
|
||||
)
|
||||
"
|
||||
@delete="() => triggerFileDelete(value.pathname)"
|
||||
|
|
@ -320,7 +333,7 @@ async function submitFileForm(
|
|||
class="text-overflow-handle block q-px-md text-center"
|
||||
style="max-width: 100%"
|
||||
>
|
||||
{{ getFileNameFormat(value.fileName) }}
|
||||
{{ value.title }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -369,12 +382,7 @@ async function submitFileForm(
|
|||
v-model:description="fileFormData.description"
|
||||
v-model:keyword="fileFormData.keyword"
|
||||
v-model:category="fileFormData.category"
|
||||
@filechange="
|
||||
(name: string) => (
|
||||
(fileFormError.fileExist = checkFile(name)),
|
||||
(fileFormError.fileName2Long = checkFileName(name))
|
||||
)
|
||||
"
|
||||
@filechange="(name: string) => (fileFormError.fileExist = checkFile(name))"
|
||||
@submit="submitFileForm"
|
||||
/>
|
||||
|
||||
|
|
@ -426,7 +434,7 @@ async function submitFileForm(
|
|||
.add-button {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 40%;
|
||||
right: 30%;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,17 +6,17 @@ defineEmits(['edit', 'delete'])
|
|||
<q-btn @click.stop icon="more_vert" color="grey" flat dense>
|
||||
<q-menu auto-close>
|
||||
<q-list dense>
|
||||
<q-item clickable>
|
||||
<q-item-section @click.prevent.stop="() => $emit('edit')">
|
||||
<div class="row items-center">
|
||||
<q-item clickable @click="() => $emit('edit')">
|
||||
<q-item-section>
|
||||
<div class="row items-center white ">
|
||||
<q-icon name="edit" color="positive" />
|
||||
<span class="q-ml-sm">แก้ไข</span>
|
||||
</div>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item clickable>
|
||||
<q-item-section @click.prevent.stop="() => $emit('delete')">
|
||||
<div class="row items-center">
|
||||
<q-item clickable @click="() => $emit('delete')">
|
||||
<q-item-section>
|
||||
<div class="row items-center white ">
|
||||
<q-icon name="delete" color="negative" />
|
||||
<span class="q-ml-sm">ลบ</span>
|
||||
</div>
|
||||
|
|
@ -26,3 +26,16 @@ defineEmits(['edit', 'delete'])
|
|||
</q-menu>
|
||||
</q-btn>
|
||||
</template>
|
||||
|
||||
|
||||
<style scoped>
|
||||
.white {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
display: block;
|
||||
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,13 +4,19 @@ import { useSearchDataStore } from '@/stores/searched-data'
|
|||
import { useFileInfoStore } from '@/stores/file-info-data'
|
||||
import FileIcon from '@/components/FileIcon.vue'
|
||||
import type { QTableProps } from 'quasar'
|
||||
import { onMounted, ref, watch } from 'vue'
|
||||
|
||||
defineProps<{
|
||||
viewMode: 'view_list' | 'view_module'
|
||||
}>()
|
||||
|
||||
const { foundFile } = storeToRefs(useSearchDataStore())
|
||||
const { getFileInfo, getSize, getType, getFileNameFormat } = useFileInfoStore()
|
||||
const { getFileInfo, getSize, getType } = useFileInfoStore()
|
||||
const keywordList = ref<string[]>([])
|
||||
const categoryList = ref<string[]>([])
|
||||
const selectKeyword = ref<string[]>([])
|
||||
const selectCategory = ref<string[]>([])
|
||||
const filterFoundFile = ref<any>()
|
||||
const columns: QTableProps['columns'] = [
|
||||
{
|
||||
name: 'name',
|
||||
|
|
@ -46,12 +52,81 @@ const columns: QTableProps['columns'] = [
|
|||
style: 'width: 20px',
|
||||
},
|
||||
]
|
||||
|
||||
function filterSearch() {
|
||||
function updateList() {
|
||||
keywordList.value = []
|
||||
categoryList.value = []
|
||||
foundFile.value.forEach((obj) => {
|
||||
obj.keyword.forEach((keyword) => {
|
||||
if (!keywordList.value.includes(keyword)) {
|
||||
keywordList.value.push(keyword)
|
||||
}
|
||||
})
|
||||
obj.category.forEach((category) => {
|
||||
if (!categoryList.value.includes(category)) {
|
||||
categoryList.value.push(category)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function filterArray() {
|
||||
if (!(selectKeyword.value.length || selectCategory.value.length)) {
|
||||
filterFoundFile.value = foundFile.value
|
||||
} else {
|
||||
filterFoundFile.value = foundFile.value.filter(
|
||||
(entry) =>
|
||||
entry.keyword.some((kw) => selectKeyword.value.includes(kw)) ||
|
||||
entry.category.some((kw) => selectCategory.value.includes(kw)),
|
||||
)
|
||||
}
|
||||
}
|
||||
updateList()
|
||||
filterArray()
|
||||
}
|
||||
|
||||
watch(
|
||||
[
|
||||
() => foundFile.value,
|
||||
() => selectKeyword.value,
|
||||
() => selectCategory.value,
|
||||
],
|
||||
filterSearch,
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
filterSearch()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="row grid q-pt-md q-gutter-sm">
|
||||
<q-select
|
||||
outlined
|
||||
dense
|
||||
multiple
|
||||
use-chips
|
||||
v-model="selectKeyword"
|
||||
:options="keywordList"
|
||||
style="width: 100%"
|
||||
label="คำสำคัญ"
|
||||
/>
|
||||
<q-select
|
||||
outlined
|
||||
dense
|
||||
multiple
|
||||
use-chips
|
||||
v-model="selectCategory"
|
||||
:options="categoryList"
|
||||
style="width: 100%"
|
||||
label="กลุ่ม/หมวดหมู่"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-if="viewMode === 'view_list' && foundFile.length > 0">
|
||||
<div class="grid q-mt-md">
|
||||
<div v-for="(value, index) in foundFile" :key="value.title">
|
||||
<div v-for="(value, index) in filterFoundFile" :key="value.title">
|
||||
<div
|
||||
:style="{
|
||||
position: 'relative',
|
||||
|
|
@ -63,7 +138,7 @@ const columns: QTableProps['columns'] = [
|
|||
maxWidth: '100%',
|
||||
}"
|
||||
class="box"
|
||||
@click="() => getFileInfo(foundFile[index])"
|
||||
@click="() => getFileInfo(filterFoundFile[index])"
|
||||
>
|
||||
<div class="q-px-md flex items-center justify-center">
|
||||
<file-icon
|
||||
|
|
@ -75,7 +150,7 @@ const columns: QTableProps['columns'] = [
|
|||
class="text-overflow-handle block q-px-md text-center"
|
||||
style="max-width: 100%"
|
||||
>
|
||||
{{ getFileNameFormat(value.fileName) }}
|
||||
{{ value.title }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -86,7 +161,7 @@ const columns: QTableProps['columns'] = [
|
|||
<q-table
|
||||
flat
|
||||
bordered
|
||||
:rows="foundFile"
|
||||
:rows="filterFoundFile"
|
||||
:columns="columns"
|
||||
row-key="name"
|
||||
hide-bottom
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { onMounted, onUnmounted } from 'vue'
|
||||
import { onMounted, onUnmounted, ref } from 'vue'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
|
|
@ -14,6 +14,11 @@ const props = withDefaults(
|
|||
)
|
||||
|
||||
const emit = defineEmits(['update:open', 'update:name', 'submit'])
|
||||
const offensiveWord = ref<boolean>(false)
|
||||
|
||||
function checkOffensiveWord(input: string) {
|
||||
return /[\\?%:|"<>#]/.test(input)
|
||||
}
|
||||
|
||||
function reset() {
|
||||
emit('update:name', undefined)
|
||||
|
|
@ -48,6 +53,7 @@ onUnmounted(() => window.addEventListener('keydown', keydown))
|
|||
:width="300"
|
||||
:breakpoint="500"
|
||||
:model-value="open"
|
||||
@update:model-value="(v) => $emit('update:open', v)"
|
||||
>
|
||||
<q-form @submit.prevent="submit">
|
||||
<q-toolbar class="q-mb-md q-pa-none">
|
||||
|
|
@ -66,19 +72,32 @@ onUnmounted(() => window.addEventListener('keydown', keydown))
|
|||
dense
|
||||
icon="close"
|
||||
color="red"
|
||||
@click="() => $emit('update:open', !open)"
|
||||
@click="
|
||||
() => {
|
||||
offensiveWord = false
|
||||
$emit('update:open', !open)
|
||||
}
|
||||
"
|
||||
/>
|
||||
</q-toolbar>
|
||||
|
||||
<section class="q-mb-md">
|
||||
<span class="text-weight-bold">ชื่อ{{ tree }}</span>
|
||||
<q-input
|
||||
ref="nameInput"
|
||||
outlined
|
||||
dense
|
||||
class="q-my-sm"
|
||||
placeholder="กรอกชื่อ"
|
||||
:model-value="name"
|
||||
@update:model-value="(v) => $emit('update:name', v)"
|
||||
error-message="คำต้องห้านจะเปลี่ยนเป็น - เมื่อกดสร้าง"
|
||||
:error="offensiveWord"
|
||||
@update:model-value="
|
||||
(v) => {
|
||||
$emit('update:name', v)
|
||||
offensiveWord = checkOffensiveWord(v as string)
|
||||
}
|
||||
"
|
||||
/>
|
||||
</section>
|
||||
|
||||
|
|
@ -89,7 +108,12 @@ onUnmounted(() => window.addEventListener('keydown', keydown))
|
|||
type="reset"
|
||||
color="primary"
|
||||
flat
|
||||
@click="() => ($emit('update:open', false), reset())"
|
||||
@click="
|
||||
() => {
|
||||
offensiveWord = false
|
||||
$emit('update:open', false), reset()
|
||||
}
|
||||
"
|
||||
/>
|
||||
</section>
|
||||
</q-form>
|
||||
|
|
|
|||
|
|
@ -55,14 +55,16 @@ const folderFormData = ref<{
|
|||
}>({})
|
||||
const folderFormType = ref<'edit' | 'create'>('create')
|
||||
const fileFormError = ref<{ fileExist?: boolean }>({})
|
||||
const fileExistNotification = ref<boolean>(false)
|
||||
|
||||
const fileFormState = ref<boolean>(false)
|
||||
const fileFormPath = ref<string>('')
|
||||
const fileFormData = ref<{
|
||||
file?: File
|
||||
title?: string
|
||||
description?: string
|
||||
keyword?: string
|
||||
category?: string
|
||||
keyword?: string[]
|
||||
category?: string[]
|
||||
}>({})
|
||||
const fileFormType = ref<'edit' | 'create'>('create')
|
||||
|
||||
|
|
@ -116,8 +118,8 @@ function triggerFileEdit(
|
|||
value: {
|
||||
title: string
|
||||
description: string
|
||||
keyword: string
|
||||
category: string
|
||||
keyword: string[]
|
||||
category: string[]
|
||||
},
|
||||
pathname: string
|
||||
) {
|
||||
|
|
@ -128,19 +130,31 @@ function triggerFileEdit(
|
|||
title: value.title,
|
||||
description: value.description,
|
||||
keyword: value.keyword,
|
||||
category: value.keyword,
|
||||
category: value.category,
|
||||
}
|
||||
}
|
||||
|
||||
async function submitFileForm(value: {
|
||||
mode: 'create' | 'edit'
|
||||
file: File
|
||||
title: string
|
||||
description: string
|
||||
keyword: string
|
||||
category: string
|
||||
}) {
|
||||
if (value.mode === 'create') {
|
||||
const currentParam = ref<Parameters<typeof submitFileForm>[0]>()
|
||||
|
||||
async function submitFileForm(
|
||||
value: {
|
||||
mode: 'create' | 'edit'
|
||||
file?: File
|
||||
title: string
|
||||
description: string
|
||||
keyword: string[]
|
||||
category: string[]
|
||||
},
|
||||
force = false
|
||||
) {
|
||||
currentParam.value = value
|
||||
|
||||
if (value.file && checkFile(value.file.name) && !force) {
|
||||
fileExistNotification.value = true
|
||||
return
|
||||
}
|
||||
|
||||
if (value.mode === 'create' && value.file) {
|
||||
await uploadFile(currentPath.value, value.file, {
|
||||
title: value.title,
|
||||
description: value.description,
|
||||
|
|
@ -161,6 +175,7 @@ async function submitFileForm(value: {
|
|||
}
|
||||
fileFormData.value = {}
|
||||
fileFormState.value = false
|
||||
currentParam.value = undefined
|
||||
}
|
||||
|
||||
const columnsFolder: QTableProps['columns'] = [
|
||||
|
|
@ -243,18 +258,19 @@ const onRowClick = (evt: Event, row: TreeDataFolder, index: number) => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="q-pa-md">
|
||||
<div class="q-mt-md">
|
||||
<div class="q-gutter-sm">
|
||||
<div
|
||||
class="flex flex-break d justify-between space-between"
|
||||
v-if="currentDept >= 1"
|
||||
v-if="currentDept >= 1 && props.mode == 'admin' && currentDept != 4"
|
||||
|
||||
>
|
||||
<div>
|
||||
<span class="text-h6">{{ currentLevel }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<q-btn
|
||||
v-if="props.mode == 'admin' && currentDept != 4"
|
||||
|
||||
outline
|
||||
push
|
||||
class="q-px-md q-ml-md q-py-sm"
|
||||
|
|
@ -278,6 +294,7 @@ const onRowClick = (evt: Event, row: TreeDataFolder, index: number) => {
|
|||
:rows-per-page-options="[0]"
|
||||
@row-click="onRowClick"
|
||||
class="cursor"
|
||||
v-if=" currentDept != 4 "
|
||||
>
|
||||
<template v-slot:body-cell-name="nameRow">
|
||||
<q-td style="width: 50%">
|
||||
|
|
@ -331,7 +348,7 @@ const onRowClick = (evt: Event, row: TreeDataFolder, index: number) => {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="q-pa-md" v-if="currentDept >= 3">
|
||||
<div class="q-mt-md" v-if="currentDept >= 3">
|
||||
<div class="q-gutter-sm">
|
||||
<div class="flex flex-break d justify-between space-between">
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -58,18 +58,7 @@ onMounted(getCabinet)
|
|||
<h5 class="q-my-none" v-if="mode === 'admin'">จัดเก็บเอกสาร</h5>
|
||||
<h5 class="q-my-none" v-else>สืบค้นเอกสาร</h5>
|
||||
</div>
|
||||
<div class="col-3" v-if="mode === 'admin'">
|
||||
<q-input
|
||||
rounded
|
||||
outlined
|
||||
dense
|
||||
label="ค้นหา"
|
||||
bg-color="white"
|
||||
v-model="inputSearch"
|
||||
>
|
||||
<template v-slot:append><q-icon name="search" /></template>
|
||||
</q-input>
|
||||
</div>
|
||||
<search-bar :mode="mode" v-if="mode === 'admin'" />
|
||||
</div>
|
||||
</section>
|
||||
<section
|
||||
|
|
@ -97,7 +86,7 @@ onMounted(getCabinet)
|
|||
class="bg-white rounded-borders shadow-5 relative"
|
||||
v-if="isFilePreview === false"
|
||||
>
|
||||
<search-bar v-if="mode === 'user'" />
|
||||
<search-bar :mode="mode" v-if="mode === 'user'" />
|
||||
<div class="bg-white q-pa-md">
|
||||
<div class="row items-center justify-between">
|
||||
<span class="text-body1">
|
||||
|
|
@ -107,7 +96,12 @@ onMounted(getCabinet)
|
|||
dense
|
||||
class="q-mr-sm q-px-sm"
|
||||
v-if="currentDept > 0 && isSearch === false"
|
||||
@click="() => gotoParent()"
|
||||
@click="
|
||||
() => {
|
||||
folderFormState = false
|
||||
gotoParent()
|
||||
}
|
||||
"
|
||||
>
|
||||
<q-icon name="arrow_back" size="1rem" color="primary" />
|
||||
</q-btn>
|
||||
|
|
@ -137,6 +131,7 @@ onMounted(getCabinet)
|
|||
dense
|
||||
icon="add"
|
||||
@click="() => triggerFolderCreate()"
|
||||
id="createFolder"
|
||||
/>
|
||||
</span>
|
||||
<div>
|
||||
|
|
@ -147,6 +142,7 @@ onMounted(getCabinet)
|
|||
icon="refresh"
|
||||
class="q-mr-sm"
|
||||
@click="() => getFolder(currentPath)"
|
||||
id="getFolder"
|
||||
/>
|
||||
<q-btn
|
||||
flat
|
||||
|
|
@ -159,6 +155,7 @@ onMounted(getCabinet)
|
|||
viewMode === 'view_list' ? 'view_module' : 'view_list'
|
||||
}
|
||||
"
|
||||
id="viewMode"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,40 +0,0 @@
|
|||
<script setup lang="ts">
|
||||
import { onMounted, ref } from "vue";
|
||||
import TagInput from "@mayank1513/vue-tag-input";
|
||||
import "@mayank1513/vue-tag-input/style.css";
|
||||
|
||||
const autocompleteItems = [
|
||||
"No dependencies",
|
||||
"Autocompletion",
|
||||
"Keep Focused",
|
||||
"Fast Settup",
|
||||
"Mini Sized",
|
||||
"Customizable",
|
||||
"Backspace/Delete to remove tag",
|
||||
"Turns red when backspace/delete is pressed",
|
||||
"Examples",
|
||||
"Docs",
|
||||
"Copy/Paste",
|
||||
]
|
||||
const tags = ref<string[]>([]);
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<q-btn @click="()=> {console.log(tags);
|
||||
}">test</q-btn>
|
||||
<tag-input tagBgColor="rgb(189, 184, 179)" :autocomplete-items="autocompleteItems" v-model="tags" />
|
||||
<!-- <q-btn
|
||||
class="q-px-md"
|
||||
label="บันทึก"
|
||||
type="submit"
|
||||
color="primary"
|
||||
dense
|
||||
@click="
|
||||
() => {
|
||||
$emit('update:drawerFile')
|
||||
|
||||
}
|
||||
"
|
||||
/> -->
|
||||
</template>
|
||||
|
|
@ -9,6 +9,8 @@ const { isAdvSearchCall } = storeToRefs(useSearchDataStore())
|
|||
const optionsField = [
|
||||
{ label: 'ชื่อเรื่อง (title)', value: 'title' },
|
||||
{ label: 'คำสำคัญ (keyword)', value: 'keyword' },
|
||||
{ label: 'หมวดหมู่ (category)', value: 'category' },
|
||||
{ label: 'เนื้อหาในไฟล์ (content)', value: 'attachment.content' },
|
||||
]
|
||||
const optionsOp = [
|
||||
{ label: 'และ', value: 'AND' },
|
||||
|
|
@ -126,6 +128,7 @@ function clearAdvSearchData() {
|
|||
</div>
|
||||
<div class="col-4 col-md-2">
|
||||
<q-select
|
||||
id="advSearchOp"
|
||||
dense
|
||||
outlined
|
||||
emit-value
|
||||
|
|
@ -136,6 +139,7 @@ function clearAdvSearchData() {
|
|||
</div>
|
||||
<div class="col-grow col-md-3">
|
||||
<q-select
|
||||
id="advSearchField"
|
||||
dense
|
||||
outlined
|
||||
emit-value
|
||||
|
|
@ -145,7 +149,13 @@ function clearAdvSearchData() {
|
|||
/>
|
||||
</div>
|
||||
<div class="col-grow">
|
||||
<q-input dense outlined v-model="item.value" placeholder="เอกสาร"
|
||||
<q-input
|
||||
id="advSearchValue"
|
||||
dense
|
||||
outlined
|
||||
v-model="item.value"
|
||||
placeholder="เอกสาร"
|
||||
@keydown.enter.prevent="searchSubmit()"
|
||||
><template v-slot:append>
|
||||
<q-icon
|
||||
name="close"
|
||||
|
|
@ -181,17 +191,21 @@ function clearAdvSearchData() {
|
|||
<div class="row q-col-gutter-md q-pb-md">
|
||||
<div class="col-12 col-md-5">
|
||||
<q-input
|
||||
id="advSearchKeyword"
|
||||
dense
|
||||
outlined
|
||||
placeholder="คำสำคัญ:"
|
||||
placeholder="คำสำคัญ"
|
||||
@keydown.enter.prevent="searchSubmit()"
|
||||
v-model="advSearchDataField.keyword"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-12 col-md-grow">
|
||||
<q-input
|
||||
id="advSearchDes"
|
||||
dense
|
||||
outlined
|
||||
placeholder="รายละเอียด:"
|
||||
placeholder="รายละเอียด"
|
||||
@keydown.enter.prevent="searchSubmit()"
|
||||
v-model="advSearchDataField.description"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ async function downloadSubmit(path: any) {
|
|||
color="primary"
|
||||
/>
|
||||
</q-btn>
|
||||
{{ getFileNameFormat(fileInfo?.fileName) }}</span
|
||||
{{ fileInfo?.title }}</span
|
||||
>
|
||||
</div>
|
||||
|
||||
|
|
@ -85,7 +85,7 @@ async function downloadSubmit(path: any) {
|
|||
class="text-overflow-handle block q-px-md text-center"
|
||||
style="max-width: 100%"
|
||||
>
|
||||
{{ getFileNameFormat(fileInfo?.fileName) }}
|
||||
{{ fileInfo?.title }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="column q-py-sm">
|
||||
|
|
@ -133,12 +133,7 @@ async function downloadSubmit(path: any) {
|
|||
<span>กลุ่ม/หมวดหมู่</span>
|
||||
</div>
|
||||
<div class="col-grow">
|
||||
<span
|
||||
class="text-grey"
|
||||
v-for="category in fileInfo?.category"
|
||||
:key="category"
|
||||
>{{ category }}</span
|
||||
>
|
||||
<span class="text-grey">{{ fileInfo?.category.join(', ') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<q-separator />
|
||||
|
|
@ -147,12 +142,7 @@ async function downloadSubmit(path: any) {
|
|||
<span>คำสำคัญ</span>
|
||||
</div>
|
||||
<div class="col-grow">
|
||||
<span
|
||||
class="text-grey"
|
||||
v-for="keyword in fileInfo?.keyword"
|
||||
:key="keyword"
|
||||
>{{ keyword }}</span
|
||||
>
|
||||
<span class="text-grey">{{ fileInfo?.keyword.join(', ') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<q-separator />
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ const advSearchComp = ref<InstanceType<typeof AdvancedSearch>>()
|
|||
const optionsField = [
|
||||
{ label: 'ชื่อเรื่อง (title)', value: 'title' },
|
||||
{ label: 'คำสำคัญ (keyword)', value: 'keyword' },
|
||||
{ label: 'หมวดหมู่ (category)', value: 'category' },
|
||||
{ label: 'เนื้อหาในไฟล์ (content)', value: 'attachment.content' },
|
||||
]
|
||||
const searchData = ref<{
|
||||
field: string
|
||||
|
|
@ -31,41 +33,48 @@ const submitSearchData = ref<{
|
|||
AND: [],
|
||||
OR: [],
|
||||
})
|
||||
const props = defineProps<{
|
||||
mode: 'admin' | 'user'
|
||||
}>()
|
||||
|
||||
async function searchSubmit() {
|
||||
if (searchData.value.value.trim() !== '') {
|
||||
submitSearchData.value = { AND: [], OR: [] }
|
||||
|
||||
submitSearchData.value.AND.push({
|
||||
field: searchData.value.field,
|
||||
value: searchData.value.value,
|
||||
})
|
||||
submitSearchData.value.AND.push({
|
||||
field: 'fileName',
|
||||
value: searchData.value.value,
|
||||
})
|
||||
|
||||
if (isAdvSearchCall.value && advSearchComp.value) {
|
||||
const advField = advSearchComp.value.advSearchDataField
|
||||
const advRow = advSearchComp.value.advSearchDataRow
|
||||
|
||||
advRow.forEach((d: { field: string; value: string; op: string }) => {
|
||||
if (d.field && d.value.trim() !== '') {
|
||||
const op = d.op === 'AND' ? 'AND' : 'OR'
|
||||
submitSearchData.value[op].push({ field: d.field, value: d.value })
|
||||
}
|
||||
if (props.mode === 'admin') {
|
||||
optionsField.forEach((option) => {
|
||||
submitSearchData.value.OR.push({
|
||||
field: option.value,
|
||||
value: searchData.value.value,
|
||||
})
|
||||
})
|
||||
if (advField.keyword.trim() !== '') {
|
||||
submitSearchData.value.AND.push({
|
||||
field: 'keyword',
|
||||
value: advField.keyword,
|
||||
})
|
||||
}
|
||||
if (advField.description.trim() !== '') {
|
||||
submitSearchData.value.AND.push({
|
||||
field: 'description',
|
||||
value: advField.description,
|
||||
} else {
|
||||
submitSearchData.value.OR.push({
|
||||
field: searchData.value.field,
|
||||
value: searchData.value.value,
|
||||
})
|
||||
|
||||
if (isAdvSearchCall.value && advSearchComp.value) {
|
||||
const advField = advSearchComp.value.advSearchDataField
|
||||
const advRow = advSearchComp.value.advSearchDataRow
|
||||
|
||||
advRow.forEach((d: { field: string; value: string; op: string }) => {
|
||||
if (d.field && d.value.trim() !== '') {
|
||||
const op = d.op === 'AND' ? 'AND' : 'OR'
|
||||
submitSearchData.value[op].push({ field: d.field, value: d.value })
|
||||
}
|
||||
})
|
||||
if (advField.keyword.trim() !== '') {
|
||||
submitSearchData.value.AND.push({
|
||||
field: 'keyword',
|
||||
value: advField.keyword,
|
||||
})
|
||||
}
|
||||
if (advField.description.trim() !== '') {
|
||||
submitSearchData.value.AND.push({
|
||||
field: 'description',
|
||||
value: advField.description,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -73,11 +82,8 @@ async function searchSubmit() {
|
|||
loaderStore.show()
|
||||
const res = await axiosClient.post<EhrFile[]>(
|
||||
`${import.meta.env.VITE_API_ENDPOINT}/search`,
|
||||
submitSearchData.value
|
||||
submitSearchData.value,
|
||||
)
|
||||
console.log(submitSearchData.value);
|
||||
console.log(res.data);
|
||||
|
||||
getFoundFile(res.data)
|
||||
isSearch.value = true
|
||||
} catch (error) {
|
||||
|
|
@ -90,59 +96,78 @@ async function searchSubmit() {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="q-pa-md bg-grey-1">
|
||||
<div class="row items-center q-col-gutter-md">
|
||||
<div class="col-12 col-md-3">
|
||||
<q-select
|
||||
dense
|
||||
outlined
|
||||
emit-value
|
||||
map-options
|
||||
class="bg-white"
|
||||
v-model="searchData.field"
|
||||
:options="optionsField"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-12 col-md-grow">
|
||||
<q-input
|
||||
class="bg-white"
|
||||
dense
|
||||
outlined
|
||||
v-model="searchData.value"
|
||||
placeholder="เอกสาร"
|
||||
@keydown.enter.prevent="searchSubmit"
|
||||
>
|
||||
<template v-slot:append>
|
||||
<q-icon
|
||||
name="close"
|
||||
@click="() => (searchData.value = '', isSearch = false)"
|
||||
class="cursor-pointer"
|
||||
/>
|
||||
</template>
|
||||
</q-input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column">
|
||||
<div class="row items-center justify-between q-gutter-y-md q-pt-sm">
|
||||
<div class="column col-grow">
|
||||
<advanced-search
|
||||
ref="advSearchComp"
|
||||
:searchSubmit="searchSubmit"
|
||||
:submit-search-data="submitSearchData"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="isAdvSearchCall === false">
|
||||
<q-btn
|
||||
style="width: 150px"
|
||||
color="primary"
|
||||
label="ค้นหา"
|
||||
icon="mdi-magnify"
|
||||
@click="searchSubmit"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-3" v-if="mode === 'admin'">
|
||||
<q-input
|
||||
rounded
|
||||
outlined
|
||||
dense
|
||||
label="ค้นหา"
|
||||
bg-color="white"
|
||||
v-model="searchData.value"
|
||||
id="inputSearch"
|
||||
@keydown.enter.prevent="searchSubmit"
|
||||
>
|
||||
<template v-slot:append><q-icon name="search" /></template>
|
||||
</q-input>
|
||||
</div>
|
||||
|
||||
<div v-if="mode === 'user'">
|
||||
<div class="q-pa-md bg-grey-1">
|
||||
<div class="row items-center q-col-gutter-md">
|
||||
<div class="col-12 col-md-3">
|
||||
<q-select
|
||||
id="searchField"
|
||||
dense
|
||||
outlined
|
||||
emit-value
|
||||
map-options
|
||||
class="bg-white"
|
||||
v-model="searchData.field"
|
||||
:options="optionsField"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-12 col-md-grow">
|
||||
<q-input
|
||||
id="searchValue"
|
||||
class="bg-white"
|
||||
dense
|
||||
outlined
|
||||
v-model="searchData.value"
|
||||
placeholder="เอกสาร"
|
||||
@keydown.enter.prevent="searchSubmit"
|
||||
>
|
||||
<template v-slot:append>
|
||||
<q-icon
|
||||
name="close"
|
||||
@click="() => ((searchData.value = ''), (isSearch = false))"
|
||||
class="cursor-pointer"
|
||||
/>
|
||||
</template>
|
||||
</q-input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column">
|
||||
<div class="row items-center justify-between q-gutter-y-md q-pt-sm">
|
||||
<div class="column col-grow">
|
||||
<advanced-search
|
||||
ref="advSearchComp"
|
||||
:searchSubmit="searchSubmit"
|
||||
:submit-search-data="submitSearchData"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="isAdvSearchCall === false">
|
||||
<q-btn
|
||||
style="width: 150px"
|
||||
color="primary"
|
||||
label="ค้นหา"
|
||||
icon="mdi-magnify"
|
||||
@click="searchSubmit"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<q-separator />
|
||||
</div>
|
||||
<q-separator />
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -40,9 +40,6 @@ export interface TreeDataFolder {
|
|||
|
||||
export const useTreeDataStore = defineStore('changeCabinet', () => {
|
||||
const loader = useLoader()
|
||||
const indexToRemove = ref<number>()
|
||||
const fileNameRemove = ref<string>('')
|
||||
|
||||
const data = ref<TreeDataFolder[]>([])
|
||||
const currentFolder = ref<TreeDataFolder[]>([])
|
||||
const currentFile = ref<EhrFile[]>([])
|
||||
|
|
@ -96,7 +93,7 @@ export const useTreeDataStore = defineStore('changeCabinet', () => {
|
|||
currentPath.value = pathname
|
||||
|
||||
const res = await axiosClient.get<EhrFolder[]>(
|
||||
`${apiEndpoint}${requestPath}`,
|
||||
`${apiEndpoint}${requestPath}`
|
||||
)
|
||||
|
||||
const list = res.data.map((v) => ({
|
||||
|
|
@ -246,9 +243,9 @@ export const useTreeDataStore = defineStore('changeCabinet', () => {
|
|||
metadata: {
|
||||
title: string
|
||||
description: string
|
||||
keyword: string
|
||||
category: string
|
||||
},
|
||||
keyword: string[]
|
||||
category: string[]
|
||||
}
|
||||
) {
|
||||
loader.show()
|
||||
|
||||
|
|
@ -268,7 +265,7 @@ export const useTreeDataStore = defineStore('changeCabinet', () => {
|
|||
{
|
||||
file: file.name,
|
||||
...metadata,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
if (res && res.data.upload) {
|
||||
|
|
@ -294,10 +291,10 @@ export const useTreeDataStore = defineStore('changeCabinet', () => {
|
|||
metadata: {
|
||||
title: string
|
||||
description: string
|
||||
keyword: string
|
||||
category: string
|
||||
keyword: string[]
|
||||
category: string[]
|
||||
},
|
||||
file?: File,
|
||||
file?: File
|
||||
) {
|
||||
loader.show()
|
||||
|
||||
|
|
@ -312,7 +309,7 @@ export const useTreeDataStore = defineStore('changeCabinet', () => {
|
|||
|
||||
const res = await axiosClient.patch<{ upload: string }>(
|
||||
`${apiEndpoint}${requestPath}`,
|
||||
{ file: file?.name, ...metadata },
|
||||
{ file: file?.name, ...metadata }
|
||||
)
|
||||
|
||||
if (res && res.data.upload) {
|
||||
|
|
@ -354,7 +351,7 @@ export const useTreeDataStore = defineStore('changeCabinet', () => {
|
|||
await getFile(currentPath.value)
|
||||
|
||||
currentFile.value = currentFile.value.filter((v) => v.pathname !== pathname)
|
||||
|
||||
listDataFile.value = currentFile.value
|
||||
return loader.hide()
|
||||
}
|
||||
|
||||
|
|
@ -366,6 +363,26 @@ export const useTreeDataStore = defineStore('changeCabinet', () => {
|
|||
return fileName.length >= 85
|
||||
}
|
||||
|
||||
async function refaceFile(pathname: string) {
|
||||
const pathArray: string[] = pathname.split('/').filter(Boolean)
|
||||
|
||||
if (pathArray.length <= 2) {
|
||||
currentFile.value = []
|
||||
return loader.hide()
|
||||
}
|
||||
|
||||
let requestPath = `cabinet/${pathArray[0]}/drawer/${pathArray[1]}`
|
||||
if (pathArray.length >= 3) requestPath += `/folder/${pathArray[2]}`
|
||||
if (pathArray.length >= 4) requestPath += `/subfolder/${pathArray[3]}`
|
||||
requestPath += '/file'
|
||||
|
||||
const res = await axiosClient.get<EhrFile[]>(`${apiEndpoint}${requestPath}`)
|
||||
|
||||
currentFile.value = res.data
|
||||
|
||||
listDataFile.value = currentFile.value
|
||||
}
|
||||
|
||||
return {
|
||||
data,
|
||||
currentFolder,
|
||||
|
|
@ -385,5 +402,6 @@ export const useTreeDataStore = defineStore('changeCabinet', () => {
|
|||
editFolder,
|
||||
checkFile,
|
||||
checkFileName,
|
||||
refaceFile,
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,66 +0,0 @@
|
|||
version: "3.8"
|
||||
|
||||
name: "ehr"
|
||||
|
||||
services:
|
||||
elasticsearch:
|
||||
build:
|
||||
context: .
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- 9200:9200
|
||||
volumes:
|
||||
- elasticsearch-data:/usr/share/elasticsearch/data
|
||||
environment:
|
||||
- xpack.security.enabled=false
|
||||
- discovery.type=single-node
|
||||
|
||||
kibana:
|
||||
image: kibana:8.10.2
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- elasticsearch
|
||||
ports:
|
||||
- 5601:5601
|
||||
volumes:
|
||||
- kibana-data:/usr/share/kibana/data
|
||||
environment:
|
||||
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
|
||||
|
||||
minio:
|
||||
image: minio/minio:latest
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- elasticsearch
|
||||
command: server --console-address ":9001" /data
|
||||
ports:
|
||||
- 9000:9000
|
||||
- 9001:9001
|
||||
volumes:
|
||||
- minio-data:/data
|
||||
environment:
|
||||
- MINIO_ROOT_USER=ehr
|
||||
- MINIO_ROOT_PASSWORD=P@ssw0rd
|
||||
|
||||
keycloak:
|
||||
image: quay.io/keycloak/keycloak:22.0.3
|
||||
restart: unless-stopped
|
||||
command:
|
||||
- start-dev
|
||||
ports:
|
||||
- 8080:8080
|
||||
volumes:
|
||||
- keycloak-data:/opt/keycloak/data
|
||||
environment:
|
||||
- KEYCLOAK_ADMIN=ehr
|
||||
- KEYCLOAK_ADMIN_PASSWORD=P@ssw0rd
|
||||
|
||||
volumes:
|
||||
elasticsearch-data:
|
||||
driver: local
|
||||
kibana-data:
|
||||
driver: local
|
||||
minio-data:
|
||||
driver: local
|
||||
keycloak-data:
|
||||
driver: local
|
||||
|
|
@ -2,6 +2,7 @@ import {
|
|||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Example,
|
||||
Get,
|
||||
Patch,
|
||||
Path,
|
||||
|
|
@ -21,7 +22,7 @@ import HttpStatusCode from "../interfaces/http-status";
|
|||
import { StorageFile } from "../interfaces/storage-fs";
|
||||
import HttpError from "../interfaces/http-error";
|
||||
|
||||
import { copyCond, pathExist } from "../utils/minio";
|
||||
import { copyCond, pathExist, replaceIllegalChars } from "../utils/minio";
|
||||
|
||||
const DEFAULT_BUCKET = process.env.MINIO_BUCKET;
|
||||
const DEFAULT_INDEX = process.env.ELASTICSEARCH_INDEX;
|
||||
|
|
@ -31,10 +32,33 @@ if (!DEFAULT_INDEX) throw Error("Default ElasticSearch index must be specified."
|
|||
|
||||
@Route("/cabinet/{cabinetName}/drawer/{drawerName}/folder/{folderName}/file")
|
||||
export class FileController extends Controller {
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
*/
|
||||
@Get("/")
|
||||
@Tags("ไฟล์")
|
||||
@Security("bearerAuth")
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
@Example([
|
||||
{
|
||||
pathname: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/เอกสาร 1",
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/",
|
||||
title: "เอกสาร",
|
||||
description: "เอกสารการเงิน",
|
||||
category: ["บัญชี"],
|
||||
keyword: ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"],
|
||||
upload: false,
|
||||
fileName: "เอกสาร 1",
|
||||
fileSize: 10240,
|
||||
fileType: "application/pdf",
|
||||
createdAt: "2021-07-20T12:33:13.018Z",
|
||||
createdBy: "admin",
|
||||
updatedAt: "2021-07-20T12:33:13.018Z",
|
||||
updatedBy: "admin",
|
||||
},
|
||||
])
|
||||
public async getFile(
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
|
|
@ -62,6 +86,11 @@ export class FileController extends Controller {
|
|||
return records;
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
*/
|
||||
@Post("/")
|
||||
@Tags("ไฟล์")
|
||||
@Security("bearerAuth", ["admin"])
|
||||
|
|
@ -70,15 +99,46 @@ export class FileController extends Controller {
|
|||
"ตำแหน่งที่ระบุไม่พบ กรุณาเตรียมตำแหน่งที่ต้องการก่อนดำเนินการ",
|
||||
)
|
||||
@SuccessResponse(HttpStatusCode.CREATED, "สำเร็จ")
|
||||
@Example({
|
||||
pathname: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/เอกสาร 1",
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/",
|
||||
title: "เอกสาร",
|
||||
description: "เอกสารการเงิน",
|
||||
category: ["บัญชี"],
|
||||
keyword: ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"],
|
||||
upload: false,
|
||||
fileName: "เอกสาร 1",
|
||||
fileSize: 10240,
|
||||
fileType: "application/pdf",
|
||||
createdAt: "2021-07-20T12:33:13.018Z",
|
||||
createdBy: "admin",
|
||||
updatedAt: "2021-07-20T12:33:13.018Z",
|
||||
updatedBy: "admin",
|
||||
})
|
||||
public async uploadFile(
|
||||
@Request() request: { user: { preferred_username: string } },
|
||||
@Body()
|
||||
body: {
|
||||
/**
|
||||
* @example "เอกสาร 1"
|
||||
*/
|
||||
file: string;
|
||||
/**
|
||||
* @example "เอกสาร"
|
||||
*/
|
||||
title?: string;
|
||||
/**
|
||||
* @example "เอกสารการเงิน"
|
||||
*/
|
||||
description?: string;
|
||||
category?: string;
|
||||
keyword?: string;
|
||||
/**
|
||||
* @example ["บัญชี"]
|
||||
*/
|
||||
category?: string[];
|
||||
/**
|
||||
* @example ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"]
|
||||
*/
|
||||
keyword?: string[];
|
||||
},
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
|
|
@ -89,7 +149,7 @@ export class FileController extends Controller {
|
|||
}
|
||||
|
||||
const basePath = `${cabinetName}/${drawerName}/${folderName}/`;
|
||||
const pathname = `${basePath}${body.file}`;
|
||||
const pathname = `${basePath}${replaceIllegalChars(body.file)}`;
|
||||
|
||||
if (!(await pathExist(DEFAULT_BUCKET!, basePath))) {
|
||||
throw new HttpError(
|
||||
|
|
@ -120,13 +180,13 @@ export class FileController extends Controller {
|
|||
const metadata: Partial<StorageFile> = {
|
||||
pathname,
|
||||
path: basePath,
|
||||
fileName: body.file,
|
||||
fileName: replaceIllegalChars( body.file ),
|
||||
fileSize: 0,
|
||||
fileType: "",
|
||||
title: body.title ?? "",
|
||||
description: body.description ?? "",
|
||||
category: body.category?.split(",") ?? [],
|
||||
keyword: body.keyword?.split(",") ?? [],
|
||||
category: body.category ?? [],
|
||||
keyword: body.keyword ?? [],
|
||||
upload: false,
|
||||
createdAt: new Date().toISOString(),
|
||||
createdBy: rec ? rec.createdBy : "n/a",
|
||||
|
|
@ -150,6 +210,12 @@ export class FileController extends Controller {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
* @example fileName "เอกสาร 1"
|
||||
*/
|
||||
@Patch("/{fileName}")
|
||||
@Tags("ไฟล์")
|
||||
@Security("bearerAuth", ["admin"])
|
||||
|
|
@ -164,11 +230,26 @@ export class FileController extends Controller {
|
|||
@Path() fileName: string,
|
||||
@Body()
|
||||
body: {
|
||||
/**
|
||||
* @example "เอกสารใหม่"
|
||||
*/
|
||||
file?: string;
|
||||
/**
|
||||
* @example "เอกสารการเงิน"
|
||||
*/
|
||||
title?: string;
|
||||
/**
|
||||
* @example "เอกสารการเงินฉบับใหม่"
|
||||
*/
|
||||
description?: string;
|
||||
category?: string;
|
||||
keyword?: string;
|
||||
/**
|
||||
* @example ["บัญชี"]
|
||||
*/
|
||||
category?: string[];
|
||||
/**
|
||||
* @example ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"]
|
||||
*/
|
||||
keyword?: string[];
|
||||
},
|
||||
): Promise<void | { upload: string }> {
|
||||
if (body.file && body.file.length > 85) {
|
||||
|
|
@ -191,7 +272,7 @@ export class FileController extends Controller {
|
|||
|
||||
// assume user will probably replace file by re-upload but maybe just rename
|
||||
if (body.file) {
|
||||
const destination = `${basePath}${body.file}`;
|
||||
const destination = `${basePath}${replaceIllegalChars(body.file)}`;
|
||||
const source = `/${DEFAULT_BUCKET}/${basePath}${fileName}`;
|
||||
const copy = await minioClient.copyObject(DEFAULT_BUCKET!, destination, source, copyCond);
|
||||
|
||||
|
|
@ -212,7 +293,7 @@ export class FileController extends Controller {
|
|||
doc: {
|
||||
pathname: destination,
|
||||
path: basePath,
|
||||
fileName: body.file,
|
||||
fileName: replaceIllegalChars(body.file),
|
||||
updatedAt: new Date().toISOString(),
|
||||
updatedBy: request.user.preferred_username ?? "n/a",
|
||||
},
|
||||
|
|
@ -238,8 +319,6 @@ export class FileController extends Controller {
|
|||
id,
|
||||
doc: {
|
||||
...body,
|
||||
keyword: body.keyword?.split(","),
|
||||
category: body.category?.split(","),
|
||||
updatedAt: new Date().toISOString(),
|
||||
updatedBy: request.user.preferred_username ?? "n/a",
|
||||
},
|
||||
|
|
@ -252,12 +331,18 @@ export class FileController extends Controller {
|
|||
? {
|
||||
upload: await minioClient.presignedPutObject(
|
||||
DEFAULT_BUCKET!,
|
||||
`${basePath}${body.file ?? fileName}`,
|
||||
`${basePath}${replaceIllegalChars(body.file) ?? fileName}`,
|
||||
),
|
||||
}
|
||||
: this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
* @example fileName "เอกสารใหม่"
|
||||
*/
|
||||
@Delete("/{fileName}")
|
||||
@Tags("ไฟล์")
|
||||
@Security("bearerAuth", ["admin"])
|
||||
|
|
@ -275,6 +360,12 @@ export class FileController extends Controller {
|
|||
return this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
* @example fileName "เอกสารใหม่"
|
||||
*/
|
||||
@Get("/{fileName}")
|
||||
@Tags("ดาวน์โหลด")
|
||||
@Security("bearerAuth")
|
||||
|
|
|
|||
|
|
@ -1,104 +0,0 @@
|
|||
import { Body, Controller, Get, Path, Post, Put, Query, Route, SuccessResponse } from "tsoa";
|
||||
import { replaceIllegalChars } from "../utils/minio";
|
||||
import minioClient from "../minio";
|
||||
import HttpStatusCode from "../interfaces/http-status";
|
||||
import HttpError from "../interfaces/http-error";
|
||||
|
||||
const DEFAULT_BUCKET = process.env.MINIO_BUCKET;
|
||||
const DEFAULT_INDEX = process.env.ELASTICSEARCH_INDEX;
|
||||
|
||||
if (!DEFAULT_BUCKET) throw Error("Default MinIO bucket must be specified.");
|
||||
if (!DEFAULT_INDEX) throw Error("Default ElasticSearch index must be specified.");
|
||||
|
||||
@Route("/storage/d")
|
||||
export class StorageController extends Controller {
|
||||
@Get()
|
||||
@SuccessResponse(HttpStatusCode.OK, "Success")
|
||||
public async getFolder(@Query() path: string, @Query() bucket?: string) {
|
||||
const list = await new Promise<{ pathname: string; name: string }[]>((resolve, reject) => {
|
||||
const item: { pathname: string; name: string }[] = [];
|
||||
|
||||
const stream = minioClient.listObjectsV2(bucket ?? DEFAULT_BUCKET!, path);
|
||||
stream.on("data", (v) => {
|
||||
if (v && v.prefix) {
|
||||
item.push({
|
||||
pathname: v.prefix,
|
||||
name: v.prefix.slice(path?.length).split("/")[0],
|
||||
});
|
||||
}
|
||||
});
|
||||
stream.on("end", () => resolve(item));
|
||||
stream.on("error", () => reject(new Error("เกิดข้อผิดพลาดกับระบบจัดการไฟล์")));
|
||||
});
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
@Post()
|
||||
@SuccessResponse(HttpStatusCode.CREATED, "Success")
|
||||
public async createFolder(@Query() path: string, @Query() bucket?: string) {
|
||||
const fragments = path.split("/").filter(Boolean);
|
||||
|
||||
await Promise.all(
|
||||
fragments.map(async (_, i, a) => {
|
||||
const path = [...a.slice(0, i + 1)].map((x) => replaceIllegalChars(x)).join("/");
|
||||
const created = await minioClient
|
||||
.putObject(bucket ?? DEFAULT_BUCKET!, `${path}/.keep`, "", 0)
|
||||
.catch((e) => console.error(e));
|
||||
if (!created) throw new Error("เกิดข้อผิดพลาดกับระบบจัดการไฟล์");
|
||||
}),
|
||||
);
|
||||
|
||||
return this.setStatus(HttpStatusCode.CREATED);
|
||||
}
|
||||
|
||||
@Put()
|
||||
@SuccessResponse(HttpStatusCode.NO_CONTENT, "Success")
|
||||
public async updateFolder(
|
||||
@Body()
|
||||
body: {
|
||||
from: {
|
||||
bucket: string;
|
||||
path: string;
|
||||
};
|
||||
to: {
|
||||
bucket: string;
|
||||
path: string;
|
||||
};
|
||||
},
|
||||
) {
|
||||
const src = body.from.path.split("/").filter(Boolean).join("/");
|
||||
const dst = body.to.path.split("/").filter(Boolean).join("/");
|
||||
|
||||
if (
|
||||
!Boolean(
|
||||
await minioClient
|
||||
.statObject(DEFAULT_BUCKET!, `${dst.replace(/^\/|\/$/g, "")}/.keep`)
|
||||
.catch((e) => {
|
||||
if (e.code === "NotFound") return false;
|
||||
throw new Error(`Minio Error: ${e}`);
|
||||
}),
|
||||
)
|
||||
)
|
||||
throw new HttpError(HttpStatusCode.NOT_FOUND, "Destination Not Found");
|
||||
|
||||
const list = await new Promise<{ pathname: string; name: string }[]>((resolve, reject) => {
|
||||
const item: { pathname: string; name: string }[] = [];
|
||||
|
||||
const stream = minioClient.listObjectsV2(body.from.bucket, src);
|
||||
|
||||
stream.on("data", (v) => {
|
||||
if (v && v.prefix) {
|
||||
item.push({
|
||||
pathname: v.prefix,
|
||||
name: v.prefix.slice(src.length).split("/")[0],
|
||||
});
|
||||
}
|
||||
});
|
||||
stream.on("error", (e) => reject(new Error(`Minio Error: ${e}`)));
|
||||
stream.on("end", () => resolve(item));
|
||||
});
|
||||
|
||||
return this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ import {
|
|||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Example,
|
||||
Get,
|
||||
Patch,
|
||||
Path,
|
||||
|
|
@ -21,7 +22,7 @@ import HttpStatusCode from "../interfaces/http-status";
|
|||
import { StorageFile } from "../interfaces/storage-fs";
|
||||
import HttpError from "../interfaces/http-error";
|
||||
|
||||
import { copyCond, pathExist } from "../utils/minio";
|
||||
import { copyCond, pathExist, replaceIllegalChars } from "../utils/minio";
|
||||
|
||||
const DEFAULT_BUCKET = process.env.MINIO_BUCKET;
|
||||
const DEFAULT_INDEX = process.env.ELASTICSEARCH_INDEX;
|
||||
|
|
@ -33,10 +34,34 @@ if (!DEFAULT_INDEX) throw Error("Default ElasticSearch index must be specified."
|
|||
"/cabinet/{cabinetName}/drawer/{drawerName}/folder/{folderName}/subfolder/{subFolderName}/file",
|
||||
)
|
||||
export class SubFolderFileController extends Controller {
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
* @example subFolderName "แฟ้มย่อย 1"
|
||||
*/
|
||||
@Get("/")
|
||||
@Tags("ไฟล์")
|
||||
@Security("bearerAuth")
|
||||
@SuccessResponse(HttpStatusCode.OK, "สำเร็จ")
|
||||
@Example([
|
||||
{
|
||||
pathname: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/แฟ้มย่อย 1/เอกสาร 1",
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/แฟ้มย่อย 1/",
|
||||
title: "เอกสาร",
|
||||
description: "เอกสารการเงิน",
|
||||
category: ["บัญชี"],
|
||||
keyword: ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"],
|
||||
upload: false,
|
||||
fileName: "เอกสาร 1",
|
||||
fileSize: 10240,
|
||||
fileType: "application/pdf",
|
||||
createdAt: "2021-07-20T12:33:13.018Z",
|
||||
createdBy: "admin",
|
||||
updatedAt: "2021-07-20T12:33:13.018Z",
|
||||
updatedBy: "admin",
|
||||
},
|
||||
])
|
||||
public async getFile(
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
|
|
@ -65,6 +90,12 @@ export class SubFolderFileController extends Controller {
|
|||
return records;
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
* @example subFolderName "แฟ้มย่อย 1"
|
||||
*/
|
||||
@Post("/")
|
||||
@Tags("ไฟล์")
|
||||
@Security("bearerAuth", ["admin"])
|
||||
|
|
@ -73,15 +104,46 @@ export class SubFolderFileController extends Controller {
|
|||
"ตำแหน่งที่ระบุไม่พบ กรุณาเตรียมตำแหน่งที่ต้องการก่อนดำเนินการ",
|
||||
)
|
||||
@SuccessResponse(HttpStatusCode.CREATED, "สำเร็จ")
|
||||
@Example({
|
||||
pathname: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/แฟ้มย่อย 1/เอกสาร 1",
|
||||
path: "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/แฟ้มย่อย 1/",
|
||||
title: "เอกสาร",
|
||||
description: "เอกสารการเงิน",
|
||||
category: ["บัญชี"],
|
||||
keyword: ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"],
|
||||
upload: false,
|
||||
fileName: "เอกสาร 1",
|
||||
fileSize: 10240,
|
||||
fileType: "application/pdf",
|
||||
createdAt: "2021-07-20T12:33:13.018Z",
|
||||
createdBy: "admin",
|
||||
updatedAt: "2021-07-20T12:33:13.018Z",
|
||||
updatedBy: "admin",
|
||||
})
|
||||
public async uploadFile(
|
||||
@Request() request: { user: { preferred_username: string } },
|
||||
@Body()
|
||||
body: {
|
||||
/**
|
||||
* @example "เอกสาร 1"
|
||||
*/
|
||||
file: string;
|
||||
/**
|
||||
* @example "เอกสาร"
|
||||
*/
|
||||
title?: string;
|
||||
/**
|
||||
* @example "เอกสารการเงิน"
|
||||
*/
|
||||
description?: string;
|
||||
category?: string;
|
||||
keyword?: string;
|
||||
/**
|
||||
* @example ["บัญชี"]
|
||||
*/
|
||||
category?: string[];
|
||||
/**
|
||||
* @example ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"]
|
||||
*/
|
||||
keyword?: string[];
|
||||
},
|
||||
@Path() cabinetName: string,
|
||||
@Path() drawerName: string,
|
||||
|
|
@ -93,7 +155,7 @@ export class SubFolderFileController extends Controller {
|
|||
}
|
||||
|
||||
const basePath = `${cabinetName}/${drawerName}/${folderName}/${subFolderName}/`;
|
||||
const pathname = `${basePath}${body.file}`;
|
||||
const pathname = `${basePath}${replaceIllegalChars(body.file)}`;
|
||||
|
||||
if (!(await pathExist(DEFAULT_BUCKET!, basePath))) {
|
||||
throw new HttpError(
|
||||
|
|
@ -124,13 +186,13 @@ export class SubFolderFileController extends Controller {
|
|||
const metadata: Partial<StorageFile> = {
|
||||
pathname,
|
||||
path: basePath,
|
||||
fileName: body.file,
|
||||
fileName: replaceIllegalChars(body.file),
|
||||
fileSize: 0,
|
||||
fileType: "",
|
||||
title: body.title ?? "",
|
||||
description: body.description ?? "",
|
||||
category: body.category?.split(",") ?? [],
|
||||
keyword: body.keyword?.split(",") ?? [],
|
||||
category: body.category ?? [],
|
||||
keyword: body.keyword ?? [],
|
||||
upload: false,
|
||||
createdAt: new Date().toISOString(),
|
||||
createdBy: rec ? rec.createdBy : "n/a",
|
||||
|
|
@ -154,6 +216,13 @@ export class SubFolderFileController extends Controller {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
* @example subFolderName "แฟ้มย่อย 1"
|
||||
* @example fileName "เอกสาร 1"
|
||||
*/
|
||||
@Patch("/{fileName}")
|
||||
@Tags("ไฟล์")
|
||||
@Security("bearerAuth", ["admin"])
|
||||
|
|
@ -168,11 +237,26 @@ export class SubFolderFileController extends Controller {
|
|||
@Path() fileName: string,
|
||||
@Body()
|
||||
body: {
|
||||
/**
|
||||
* @example "เอกสารใหม่"
|
||||
*/
|
||||
file?: string;
|
||||
/**
|
||||
* @example "เอกสารการเงิน"
|
||||
*/
|
||||
title?: string;
|
||||
/**
|
||||
* @example "เอกสารการเงินฉบับใหม่"
|
||||
*/
|
||||
description?: string;
|
||||
category?: string;
|
||||
keyword?: string;
|
||||
/**
|
||||
* @example ["บัญชี"]
|
||||
*/
|
||||
category?: string[];
|
||||
/**
|
||||
* @example ["เงิน", "บัญชี", "รายจ่าย", "รายรับ"]
|
||||
*/
|
||||
keyword?: string[];
|
||||
},
|
||||
) {
|
||||
if (body.file && body.file.length > 85) {
|
||||
|
|
@ -195,7 +279,7 @@ export class SubFolderFileController extends Controller {
|
|||
|
||||
// assume user will probably replace file by re-upload but maybe just rename
|
||||
if (body.file) {
|
||||
const destination = `${basePath}${body.file}`;
|
||||
const destination = `${basePath}${replaceIllegalChars(body.file)}`;
|
||||
const source = `/${DEFAULT_BUCKET}/${basePath}${fileName}`;
|
||||
const copy = await minioClient.copyObject(DEFAULT_BUCKET!, destination, source, copyCond);
|
||||
|
||||
|
|
@ -215,7 +299,7 @@ export class SubFolderFileController extends Controller {
|
|||
id,
|
||||
doc: {
|
||||
pathname: destination,
|
||||
fileName: body.file,
|
||||
fileName: replaceIllegalChars(body.file),
|
||||
updatedAt: new Date().toISOString(),
|
||||
updatedBy: request.user.preferred_username ?? "n/a",
|
||||
},
|
||||
|
|
@ -241,8 +325,6 @@ export class SubFolderFileController extends Controller {
|
|||
id,
|
||||
doc: {
|
||||
...body,
|
||||
keyword: body.keyword?.split(","),
|
||||
category: body.category?.split(","),
|
||||
updatedAt: new Date().toISOString(),
|
||||
updatedBy: request.user.preferred_username ?? "n/a",
|
||||
},
|
||||
|
|
@ -255,12 +337,19 @@ export class SubFolderFileController extends Controller {
|
|||
? {
|
||||
upload: await minioClient.presignedPutObject(
|
||||
DEFAULT_BUCKET!,
|
||||
`${basePath}${body.file ?? fileName}`,
|
||||
`${basePath}${replaceIllegalChars(body.file) ?? fileName}`,
|
||||
),
|
||||
}
|
||||
: this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
* @example subFolderName "แฟ้มย่อย 1"
|
||||
* @example fileName "เอกสาร 1"
|
||||
*/
|
||||
@Delete("/{fileName}")
|
||||
@Tags("ไฟล์")
|
||||
@Security("bearerAuth", ["admin"])
|
||||
|
|
@ -279,6 +368,13 @@ export class SubFolderFileController extends Controller {
|
|||
return this.setStatus(HttpStatusCode.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @example cabinetName "ตู้เอกสาร 1"
|
||||
* @example drawerName "ลิ้นชัก 1"
|
||||
* @example folderName "แฟ้ม 1"
|
||||
* @example folderName "แฟ้มย่อย 1"
|
||||
* @example fileName "เอกสาร 1"
|
||||
*/
|
||||
@Get("/{fileName}")
|
||||
@Tags("ดาวน์โหลด")
|
||||
@Security("bearerAuth")
|
||||
|
|
|
|||
|
|
@ -21,9 +21,19 @@ export async function handler(key: string, event: string): Promise<boolean> {
|
|||
}
|
||||
|
||||
if (!cachedBuffer[key]) {
|
||||
const stream = await minioClient.getObject(bucket, pathname);
|
||||
const buffer = Buffer.concat(await stream.toArray());
|
||||
cachedBuffer[key] = buffer;
|
||||
try {
|
||||
const stream = await minioClient.getObject(bucket, pathname);
|
||||
const buffer = Buffer.concat(await stream.toArray());
|
||||
cachedBuffer[key] = buffer;
|
||||
} catch (e: any) {
|
||||
if (e.code === "NoSuchKey") {
|
||||
console.info(`[AMQ] Key: ${key} received but cannot be found.`)
|
||||
delete cachedBuffer[key];
|
||||
delete cachedMetadata[key];
|
||||
await ensureDelete(pathname);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!cachedMetadata[key]) {
|
||||
|
|
@ -33,6 +43,8 @@ export async function handler(key: string, event: string): Promise<boolean> {
|
|||
|
||||
const rec = await popInfo(pathname);
|
||||
|
||||
console.info(`[AMQ] Key: ${key} - ${rec ?? 'Not Found.'}`)
|
||||
|
||||
const result = rec
|
||||
? await handleFoundRecord(rec, cachedBuffer[key], cachedMetadata[key])
|
||||
: await handleNotFoundRecord(pathname, cachedBuffer[key], cachedMetadata[key]);
|
||||
|
|
|
|||
|
|
@ -13,8 +13,6 @@ import { FolderController } from './controllers/folderController';
|
|||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
import { SearchController } from './controllers/searchController';
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
import { StorageController } from './controllers/storageController';
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
import { SubFolderController } from './controllers/subFolderController';
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
import { SubFolderFileController } from './controllers/subFolderFileController';
|
||||
|
|
@ -327,7 +325,7 @@ export function RegisterRoutes(app: Router) {
|
|||
function FileController_uploadFile(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
request: {"in":"request","name":"request","required":true,"dataType":"object"},
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"keyword":{"dataType":"string"},"category":{"dataType":"string"},"description":{"dataType":"string"},"title":{"dataType":"string"},"file":{"dataType":"string","required":true}}},
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"keyword":{"dataType":"array","array":{"dataType":"string"}},"category":{"dataType":"array","array":{"dataType":"string"}},"description":{"dataType":"string"},"title":{"dataType":"string"},"file":{"dataType":"string","required":true}}},
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
|
|
@ -361,7 +359,7 @@ export function RegisterRoutes(app: Router) {
|
|||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
fileName: {"in":"path","name":"fileName","required":true,"dataType":"string"},
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"keyword":{"dataType":"string"},"category":{"dataType":"string"},"description":{"dataType":"string"},"title":{"dataType":"string"},"file":{"dataType":"string"}}},
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"keyword":{"dataType":"array","array":{"dataType":"string"}},"category":{"dataType":"array","array":{"dataType":"string"}},"description":{"dataType":"string"},"title":{"dataType":"string"},"file":{"dataType":"string"}}},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
|
@ -577,83 +575,6 @@ export function RegisterRoutes(app: Router) {
|
|||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.get('/storage/d',
|
||||
...(fetchMiddlewares<RequestHandler>(StorageController)),
|
||||
...(fetchMiddlewares<RequestHandler>(StorageController.prototype.getFolder)),
|
||||
|
||||
function StorageController_getFolder(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
path: {"in":"query","name":"path","required":true,"dataType":"string"},
|
||||
bucket: {"in":"query","name":"bucket","dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new StorageController();
|
||||
|
||||
|
||||
const promise = controller.getFolder.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 200, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.post('/storage/d',
|
||||
...(fetchMiddlewares<RequestHandler>(StorageController)),
|
||||
...(fetchMiddlewares<RequestHandler>(StorageController.prototype.createFolder)),
|
||||
|
||||
function StorageController_createFolder(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
path: {"in":"query","name":"path","required":true,"dataType":"string"},
|
||||
bucket: {"in":"query","name":"bucket","dataType":"string"},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new StorageController();
|
||||
|
||||
|
||||
const promise = controller.createFolder.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 201, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.put('/storage/d',
|
||||
...(fetchMiddlewares<RequestHandler>(StorageController)),
|
||||
...(fetchMiddlewares<RequestHandler>(StorageController.prototype.updateFolder)),
|
||||
|
||||
function StorageController_updateFolder(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"to":{"dataType":"nestedObjectLiteral","nestedProperties":{"path":{"dataType":"string","required":true},"bucket":{"dataType":"string","required":true}},"required":true},"from":{"dataType":"nestedObjectLiteral","nestedProperties":{"path":{"dataType":"string","required":true},"bucket":{"dataType":"string","required":true}},"required":true}}},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
||||
let validatedArgs: any[] = [];
|
||||
try {
|
||||
validatedArgs = getValidatedArgs(args, request, response);
|
||||
|
||||
const controller = new StorageController();
|
||||
|
||||
|
||||
const promise = controller.updateFolder.apply(controller, validatedArgs as any);
|
||||
promiseHandler(controller, promise, response, 204, next);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
app.get('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/subfolder',
|
||||
authenticateMiddleware([{"bearerAuth":[]}]),
|
||||
...(fetchMiddlewares<RequestHandler>(SubFolderController)),
|
||||
|
|
@ -808,7 +729,7 @@ export function RegisterRoutes(app: Router) {
|
|||
function SubFolderFileController_uploadFile(request: any, response: any, next: any) {
|
||||
const args = {
|
||||
request: {"in":"request","name":"request","required":true,"dataType":"object"},
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"keyword":{"dataType":"string"},"category":{"dataType":"string"},"description":{"dataType":"string"},"title":{"dataType":"string"},"file":{"dataType":"string","required":true}}},
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"keyword":{"dataType":"array","array":{"dataType":"string"}},"category":{"dataType":"array","array":{"dataType":"string"}},"description":{"dataType":"string"},"title":{"dataType":"string"},"file":{"dataType":"string","required":true}}},
|
||||
cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"},
|
||||
drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"},
|
||||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
|
|
@ -844,7 +765,7 @@ export function RegisterRoutes(app: Router) {
|
|||
folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"},
|
||||
subFolderName: {"in":"path","name":"subFolderName","required":true,"dataType":"string"},
|
||||
fileName: {"in":"path","name":"fileName","required":true,"dataType":"string"},
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"keyword":{"dataType":"string"},"category":{"dataType":"string"},"description":{"dataType":"string"},"title":{"dataType":"string"},"file":{"dataType":"string"}}},
|
||||
body: {"in":"body","name":"body","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"keyword":{"dataType":"array","array":{"dataType":"string"}},"category":{"dataType":"array","array":{"dataType":"string"}},"description":{"dataType":"string"},"title":{"dataType":"string"},"file":{"dataType":"string"}}},
|
||||
};
|
||||
|
||||
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
|
||||
|
|
|
|||
|
|
@ -599,6 +599,35 @@
|
|||
"$ref": "#/components/schemas/StorageFile"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"examples": {
|
||||
"Example 1": {
|
||||
"value": [
|
||||
{
|
||||
"pathname": "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/เอกสาร 1",
|
||||
"path": "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/",
|
||||
"title": "เอกสาร",
|
||||
"description": "เอกสารการเงิน",
|
||||
"category": [
|
||||
"บัญชี"
|
||||
],
|
||||
"keyword": [
|
||||
"เงิน",
|
||||
"บัญชี",
|
||||
"รายจ่าย",
|
||||
"รายรับ"
|
||||
],
|
||||
"upload": false,
|
||||
"fileName": "เอกสาร 1",
|
||||
"fileSize": 10240,
|
||||
"fileType": "application/pdf",
|
||||
"createdAt": "2021-07-20T12:33:13.018Z",
|
||||
"createdBy": "admin",
|
||||
"updatedAt": "2021-07-20T12:33:13.018Z",
|
||||
"updatedBy": "admin"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -619,7 +648,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "ตู้เอกสาร 1"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -627,7 +657,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "ลิ้นชัก 1"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -635,7 +666,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "แฟ้ม 1"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
@ -649,10 +681,16 @@
|
|||
"schema": {
|
||||
"properties": {
|
||||
"keyword": {
|
||||
"type": "string"
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"category": {
|
||||
"type": "string"
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
|
|
@ -704,6 +742,33 @@
|
|||
"createdAt"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"examples": {
|
||||
"Example 1": {
|
||||
"value": {
|
||||
"pathname": "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/เอกสาร 1",
|
||||
"path": "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/",
|
||||
"title": "เอกสาร",
|
||||
"description": "เอกสารการเงิน",
|
||||
"category": [
|
||||
"บัญชี"
|
||||
],
|
||||
"keyword": [
|
||||
"เงิน",
|
||||
"บัญชี",
|
||||
"รายจ่าย",
|
||||
"รายรับ"
|
||||
],
|
||||
"upload": false,
|
||||
"fileName": "เอกสาร 1",
|
||||
"fileSize": 10240,
|
||||
"fileType": "application/pdf",
|
||||
"createdAt": "2021-07-20T12:33:13.018Z",
|
||||
"createdBy": "admin",
|
||||
"updatedAt": "2021-07-20T12:33:13.018Z",
|
||||
"updatedBy": "admin"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -729,7 +794,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "ตู้เอกสาร 1"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -737,7 +803,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "ลิ้นชัก 1"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -745,7 +812,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "แฟ้ม 1"
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
|
|
@ -755,19 +823,37 @@
|
|||
"schema": {
|
||||
"properties": {
|
||||
"keyword": {
|
||||
"type": "string"
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"example": [
|
||||
"เงิน",
|
||||
"บัญชี",
|
||||
"รายจ่าย",
|
||||
"รายรับ"
|
||||
]
|
||||
},
|
||||
"category": {
|
||||
"type": "string"
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"example": [
|
||||
"บัญชี"
|
||||
]
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"example": "เอกสารการเงิน"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"example": "เอกสาร"
|
||||
},
|
||||
"file": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"example": "เอกสาร 1"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
|
|
@ -831,7 +917,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "ตู้เอกสาร 1"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -839,7 +926,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "ลิ้นชัก 1"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -847,7 +935,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "แฟ้ม 1"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -855,7 +944,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "เอกสาร 1"
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
|
|
@ -865,19 +955,37 @@
|
|||
"schema": {
|
||||
"properties": {
|
||||
"keyword": {
|
||||
"type": "string"
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"example": [
|
||||
"เงิน",
|
||||
"บัญชี",
|
||||
"รายจ่าย",
|
||||
"รายรับ"
|
||||
]
|
||||
},
|
||||
"category": {
|
||||
"type": "string"
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"example": [
|
||||
"บัญชี"
|
||||
]
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"example": "เอกสารการเงินฉบับใหม่"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"example": "เอกสารการเงิน"
|
||||
},
|
||||
"file": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"example": "เอกสารใหม่"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
|
|
@ -910,7 +1018,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "ตู้เอกสาร 1"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -918,7 +1027,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "ลิ้นชัก 1"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -926,7 +1036,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "แฟ้ม 1"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -934,7 +1045,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "เอกสารใหม่"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
@ -1054,7 +1166,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "ตู้เอกสาร 1"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -1062,7 +1175,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "ลิ้นชัก 1"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -1070,7 +1184,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "แฟ้ม 1"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -1078,7 +1193,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "เอกสารใหม่"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1372,140 +1488,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/storage/d": {
|
||||
"get": {
|
||||
"operationId": "GetFolder",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"items": {
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"pathname": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"pathname"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "query",
|
||||
"name": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "bucket",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"post": {
|
||||
"operationId": "CreateFolder",
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Success"
|
||||
}
|
||||
},
|
||||
"security": [],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "query",
|
||||
"name": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "bucket",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"put": {
|
||||
"operationId": "UpdateFolder",
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "Success"
|
||||
}
|
||||
},
|
||||
"security": [],
|
||||
"parameters": [],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"to": {
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"bucket": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"path",
|
||||
"bucket"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"from": {
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"bucket": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"path",
|
||||
"bucket"
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"to",
|
||||
"from"
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/cabinet/{cabinetName}/drawer/{drawerName}/folder/{folderName}/subfolder": {
|
||||
"get": {
|
||||
"operationId": "ListFolder",
|
||||
|
|
@ -1804,6 +1786,35 @@
|
|||
"$ref": "#/components/schemas/StorageFile"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"examples": {
|
||||
"Example 1": {
|
||||
"value": [
|
||||
{
|
||||
"pathname": "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/แฟ้มย่อย 1/เอกสาร 1",
|
||||
"path": "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/แฟ้มย่อย 1/",
|
||||
"title": "เอกสาร",
|
||||
"description": "เอกสารการเงิน",
|
||||
"category": [
|
||||
"บัญชี"
|
||||
],
|
||||
"keyword": [
|
||||
"เงิน",
|
||||
"บัญชี",
|
||||
"รายจ่าย",
|
||||
"รายรับ"
|
||||
],
|
||||
"upload": false,
|
||||
"fileName": "เอกสาร 1",
|
||||
"fileSize": 10240,
|
||||
"fileType": "application/pdf",
|
||||
"createdAt": "2021-07-20T12:33:13.018Z",
|
||||
"createdBy": "admin",
|
||||
"updatedAt": "2021-07-20T12:33:13.018Z",
|
||||
"updatedBy": "admin"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1824,7 +1835,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "ตู้เอกสาร 1"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -1832,7 +1844,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "ลิ้นชัก 1"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -1840,7 +1853,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "แฟ้ม 1"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -1848,7 +1862,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "แฟ้มย่อย 1"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
@ -1862,10 +1877,16 @@
|
|||
"schema": {
|
||||
"properties": {
|
||||
"keyword": {
|
||||
"type": "string"
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"category": {
|
||||
"type": "string"
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
|
|
@ -1917,6 +1938,33 @@
|
|||
"createdAt"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"examples": {
|
||||
"Example 1": {
|
||||
"value": {
|
||||
"pathname": "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/แฟ้มย่อย 1/เอกสาร 1",
|
||||
"path": "ตู้เอกสาร 1/ลิ้นชัก 1/แฟ้ม 1/แฟ้มย่อย 1/",
|
||||
"title": "เอกสาร",
|
||||
"description": "เอกสารการเงิน",
|
||||
"category": [
|
||||
"บัญชี"
|
||||
],
|
||||
"keyword": [
|
||||
"เงิน",
|
||||
"บัญชี",
|
||||
"รายจ่าย",
|
||||
"รายรับ"
|
||||
],
|
||||
"upload": false,
|
||||
"fileName": "เอกสาร 1",
|
||||
"fileSize": 10240,
|
||||
"fileType": "application/pdf",
|
||||
"createdAt": "2021-07-20T12:33:13.018Z",
|
||||
"createdBy": "admin",
|
||||
"updatedAt": "2021-07-20T12:33:13.018Z",
|
||||
"updatedBy": "admin"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1942,7 +1990,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "ตู้เอกสาร 1"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -1950,7 +1999,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "ลิ้นชัก 1"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -1958,7 +2008,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "แฟ้ม 1"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -1966,7 +2017,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "แฟ้มย่อย 1"
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
|
|
@ -1976,19 +2028,37 @@
|
|||
"schema": {
|
||||
"properties": {
|
||||
"keyword": {
|
||||
"type": "string"
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"example": [
|
||||
"เงิน",
|
||||
"บัญชี",
|
||||
"รายจ่าย",
|
||||
"รายรับ"
|
||||
]
|
||||
},
|
||||
"category": {
|
||||
"type": "string"
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"example": [
|
||||
"บัญชี"
|
||||
]
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"example": "เอกสารการเงิน"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"example": "เอกสาร"
|
||||
},
|
||||
"file": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"example": "เอกสาร 1"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
|
|
@ -2049,7 +2119,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "ตู้เอกสาร 1"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -2057,7 +2128,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "ลิ้นชัก 1"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -2065,7 +2137,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "แฟ้ม 1"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -2073,7 +2146,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "แฟ้มย่อย 1"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -2081,7 +2155,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "เอกสาร 1"
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
|
|
@ -2091,19 +2166,37 @@
|
|||
"schema": {
|
||||
"properties": {
|
||||
"keyword": {
|
||||
"type": "string"
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"example": [
|
||||
"เงิน",
|
||||
"บัญชี",
|
||||
"รายจ่าย",
|
||||
"รายรับ"
|
||||
]
|
||||
},
|
||||
"category": {
|
||||
"type": "string"
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"example": [
|
||||
"บัญชี"
|
||||
]
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"example": "เอกสารการเงินฉบับใหม่"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"example": "เอกสารการเงิน"
|
||||
},
|
||||
"file": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"example": "เอกสารใหม่"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
|
|
@ -2136,7 +2229,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "ตู้เอกสาร 1"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -2144,7 +2238,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "ลิ้นชัก 1"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -2152,7 +2247,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "แฟ้ม 1"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -2160,7 +2256,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "แฟ้มย่อย 1"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -2168,7 +2265,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "เอกสาร 1"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
@ -2288,7 +2386,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "ตู้เอกสาร 1"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -2296,7 +2395,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "ลิ้นชัก 1"
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
|
|
@ -2304,6 +2404,14 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"examples": {
|
||||
"Example 1": {
|
||||
"value": "แฟ้ม 1"
|
||||
},
|
||||
"Example 2": {
|
||||
"value": "แฟ้มย่อย 1"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -2320,7 +2428,8 @@
|
|||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"example": "เอกสาร 1"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import minioClient from "../minio";
|
|||
* @returns illegal character replaced path
|
||||
*/
|
||||
export function replaceIllegalChars(path: string, replace = "-") {
|
||||
return path.replace(/[/\\?%*:|"<>]/g, replace);
|
||||
return path.replace(/[/\\?%*:|"<>#]/g, replace);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"version":"Auto gen version",
|
||||
"builddate":"2020-02-02_22:22:22"
|
||||
}
|
||||
{
|
||||
"version": "dev",
|
||||
"builddate": "2020-01-01_00:00:00"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,21 +27,49 @@ esClient.ingest.putPipeline({
|
|||
},
|
||||
});
|
||||
|
||||
esClient.indices.putMapping({
|
||||
esClient.indices.create({
|
||||
index: DEFAULT_INDEX,
|
||||
body: {
|
||||
settings: {
|
||||
index: {
|
||||
analysis: {
|
||||
analyzer: {
|
||||
analyzer_shingle: {
|
||||
type: "custom",
|
||||
tokenizer: "icu_tokenizer",
|
||||
filter: ["filter_shingle"],
|
||||
},
|
||||
},
|
||||
filter: {
|
||||
filter_shingle: {
|
||||
type: "shingle",
|
||||
max_shingle_size: 3,
|
||||
min_shingle_size: 2,
|
||||
output_unigrams: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
mappings: {
|
||||
properties: {
|
||||
pathname: {
|
||||
type: "keyword",
|
||||
},
|
||||
path: {
|
||||
type: "keyword",
|
||||
},
|
||||
path: { type: "keyword" },
|
||||
pathname: { type: "keyword" },
|
||||
|
||||
fileName: { type: "text", analyzer: "analyzer_shingle" },
|
||||
title: { type: "text", analyzer: "analyzer_shingle" },
|
||||
description: { type: "text", analyzer: "analyzer_shingle" },
|
||||
|
||||
"attachment.content": { type: "text", analyzer: "analyzer_shingle" },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
minioClient.makeBucket(DEFAULT_BUCKET!, (e) => {
|
||||
if (!e) console.log("Success. Configuration is needed for Bucket Notification to AMQP.");
|
||||
console.error(e);
|
||||
if (!e) {
|
||||
console.log("Success.");
|
||||
console.log("Configuration is required for Bucket Notification to AMQP.");
|
||||
console.log("Configuration is required for Keycloak.");
|
||||
} else {
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
516
keycloak_themes/edm/login/messages/messages_en.properties
Normal file
|
|
@ -0,0 +1,516 @@
|
|||
doLogIn=LOGIN
|
||||
doRegister=Register
|
||||
doCancel=Cancel
|
||||
doSubmit=Submit
|
||||
doBack=Back
|
||||
doYes=Yes
|
||||
doNo=No
|
||||
doContinue=Continue
|
||||
doIgnore=Ignore
|
||||
doAccept=Accept
|
||||
doDecline=Decline
|
||||
doForgotPassword=Forgot Password?
|
||||
doClickHere=Click here
|
||||
doImpersonate=Impersonate
|
||||
doTryAgain=Try again
|
||||
doTryAnotherWay=Try Another Way
|
||||
doConfirmDelete=Confirm deletion
|
||||
errorDeletingAccount=Error happened while deleting account
|
||||
deletingAccountForbidden=You do not have enough permissions to delete your own account, contact admin.
|
||||
kerberosNotConfigured=Kerberos Not Configured
|
||||
kerberosNotConfiguredTitle=Kerberos Not Configured
|
||||
bypassKerberosDetail=Either you are not logged in by Kerberos or your browser is not set up for Kerberos login. Please click continue to login in through other means
|
||||
kerberosNotSetUp=Kerberos is not set up. You cannot login.
|
||||
registerTitle=Register
|
||||
loginAccountTitle=Enterprise Document Management (EDM)
|
||||
loginTitle=Sign in to {0}
|
||||
loginTitleHtml={0}
|
||||
impersonateTitle={0} Impersonate User
|
||||
impersonateTitleHtml=<strong>{0}</strong> Impersonate User
|
||||
realmChoice=Realm
|
||||
unknownUser=Unknown user
|
||||
loginTotpTitle=Mobile Authenticator Setup
|
||||
loginProfileTitle=Update Account Information
|
||||
loginIdpReviewProfileTitle=Update Account Information
|
||||
loginTimeout=Your login attempt timed out. Login will start from the beginning.
|
||||
reauthenticate=Please re-authenticate to continue
|
||||
oauthGrantTitle=Grant Access to {0}
|
||||
oauthGrantTitleHtml={0}
|
||||
oauthGrantInformation=Make sure you trust {0} by learning how {0} will handle your data.
|
||||
oauthGrantReview=You could review the
|
||||
oauthGrantTos=terms of service.
|
||||
oauthGrantPolicy=privacy policy.
|
||||
errorTitle=We are sorry...
|
||||
errorTitleHtml=We are <strong>sorry</strong> ...
|
||||
emailVerifyTitle=Email verification
|
||||
emailForgotTitle=Forgot Your Password?
|
||||
updateEmailTitle=Update email
|
||||
emailUpdateConfirmationSentTitle=Confirmation email sent
|
||||
emailUpdateConfirmationSent=A confirmation email has been sent to {0}. You must follow the instructions of the former to complete the email update.
|
||||
emailUpdatedTitle=Email updated
|
||||
emailUpdated=The account email has been successfully updated to {0}.
|
||||
updatePasswordTitle=Update password
|
||||
codeSuccessTitle=Success code
|
||||
codeErrorTitle=Error code\: {0}
|
||||
displayUnsupported=Requested display type unsupported
|
||||
browserRequired=Browser required to login
|
||||
browserContinue=Browser required to complete login
|
||||
browserContinuePrompt=Open browser and continue login? [y/n]:
|
||||
browserContinueAnswer=y
|
||||
|
||||
# Transports
|
||||
usb=USB
|
||||
nfc=NFC
|
||||
bluetooth=Bluetooth
|
||||
internal=Internal
|
||||
unknown=Unknown
|
||||
|
||||
termsTitle=Terms and Conditions
|
||||
termsText=<p>Terms and conditions to be defined</p>
|
||||
termsPlainText=Terms and conditions to be defined.
|
||||
termsAcceptanceRequired=You must agree to our terms and conditions.
|
||||
acceptTerms=I agree to the terms and conditions
|
||||
|
||||
recaptchaFailed=Invalid Recaptcha
|
||||
recaptchaNotConfigured=Recaptcha is required, but not configured
|
||||
consentDenied=Consent denied.
|
||||
|
||||
noAccount=New user?
|
||||
username=Username
|
||||
usernameOrEmail=Username
|
||||
firstName=First name
|
||||
givenName=Given name
|
||||
fullName=Full name
|
||||
lastName=Last name
|
||||
familyName=Family name
|
||||
email=Email
|
||||
password=Password
|
||||
passwordConfirm=Confirm password
|
||||
passwordNew=New Password
|
||||
passwordNewConfirm=New Password confirmation
|
||||
rememberMe=Remember me
|
||||
authenticatorCode=One-time code
|
||||
address=Address
|
||||
street=Street
|
||||
locality=City or Locality
|
||||
region=State, Province, or Region
|
||||
postal_code=Zip or Postal code
|
||||
country=Country
|
||||
emailVerified=Email verified
|
||||
website=Web page
|
||||
phoneNumber=Phone number
|
||||
phoneNumberVerified=Phone number verified
|
||||
gender=Gender
|
||||
birthday=Birthdate
|
||||
zoneinfo=Time zone
|
||||
gssDelegationCredential=GSS Delegation Credential
|
||||
logoutOtherSessions=Sign out from other devices
|
||||
|
||||
profileScopeConsentText=User profile
|
||||
emailScopeConsentText=Email address
|
||||
addressScopeConsentText=Address
|
||||
phoneScopeConsentText=Phone number
|
||||
offlineAccessScopeConsentText=Offline Access
|
||||
samlRoleListScopeConsentText=My Roles
|
||||
rolesScopeConsentText=User roles
|
||||
|
||||
restartLoginTooltip=Restart login
|
||||
|
||||
loginTotpIntro=You need to set up a One Time Password generator to access this account
|
||||
loginTotpStep1=Install one of the following applications on your mobile:
|
||||
loginTotpStep2=Open the application and scan the barcode:
|
||||
loginTotpStep3=Enter the one-time code provided by the application and click Submit to finish the setup.
|
||||
loginTotpStep3DeviceName=Provide a Device Name to help you manage your OTP devices.
|
||||
loginTotpManualStep2=Open the application and enter the key:
|
||||
loginTotpManualStep3=Use the following configuration values if the application allows setting them:
|
||||
loginTotpUnableToScan=Unable to scan?
|
||||
loginTotpScanBarcode=Scan barcode?
|
||||
loginCredential=Credential
|
||||
loginOtpOneTime=One-time code
|
||||
loginTotpType=Type
|
||||
loginTotpAlgorithm=Algorithm
|
||||
loginTotpDigits=Digits
|
||||
loginTotpInterval=Interval
|
||||
loginTotpCounter=Counter
|
||||
loginTotpDeviceName=Device Name
|
||||
|
||||
loginTotp.totp=Time-based
|
||||
loginTotp.hotp=Counter-based
|
||||
|
||||
totpAppFreeOTPName=FreeOTP
|
||||
totpAppGoogleName=Google Authenticator
|
||||
totpAppMicrosoftAuthenticatorName=Microsoft Authenticator
|
||||
|
||||
loginChooseAuthenticator=Select login method
|
||||
|
||||
oauthGrantRequest=Do you grant these access privileges?
|
||||
inResource=in
|
||||
|
||||
oauth2DeviceVerificationTitle=Device Login
|
||||
verifyOAuth2DeviceUserCode=Enter the code provided by your device and click Submit
|
||||
oauth2DeviceInvalidUserCodeMessage=Invalid code, please try again.
|
||||
oauth2DeviceExpiredUserCodeMessage=The code has expired. Please go back to your device and try connecting again.
|
||||
oauth2DeviceVerificationCompleteHeader=Device Login Successful
|
||||
oauth2DeviceVerificationCompleteMessage=You may close this browser window and go back to your device.
|
||||
oauth2DeviceVerificationFailedHeader=Device Login Failed
|
||||
oauth2DeviceVerificationFailedMessage=You may close this browser window and go back to your device and try connecting again.
|
||||
oauth2DeviceConsentDeniedMessage=Consent denied for connecting the device.
|
||||
oauth2DeviceAuthorizationGrantDisabledMessage=Client is not allowed to initiate OAuth 2.0 Device Authorization Grant. The flow is disabled for the client.
|
||||
|
||||
emailVerifyInstruction1=An email with instructions to verify your email address has been sent to your address {0}.
|
||||
emailVerifyInstruction2=Haven''t received a verification code in your email?
|
||||
emailVerifyInstruction3=to re-send the email.
|
||||
|
||||
emailLinkIdpTitle=Link {0}
|
||||
emailLinkIdp1=An email with instructions to link {0} account {1} with your {2} account has been sent to you.
|
||||
emailLinkIdp2=Haven''t received a verification code in your email?
|
||||
emailLinkIdp3=to re-send the email.
|
||||
emailLinkIdp4=If you already verified the email in different browser
|
||||
emailLinkIdp5=to continue.
|
||||
|
||||
backToLogin=« Back to Login
|
||||
|
||||
emailInstruction=Enter your username or email address and we will send you instructions on how to create a new password.
|
||||
emailInstructionUsername=Enter your username and we will send you instructions on how to create a new password.
|
||||
|
||||
copyCodeInstruction=Please copy this code and paste it into your application:
|
||||
|
||||
pageExpiredTitle=Page has expired
|
||||
pageExpiredMsg1=To restart the login process
|
||||
pageExpiredMsg2=To continue the login process
|
||||
|
||||
personalInfo=Personal Info:
|
||||
role_admin=Admin
|
||||
role_realm-admin=Realm Admin
|
||||
role_create-realm=Create realm
|
||||
role_create-client=Create client
|
||||
role_view-realm=View realm
|
||||
role_view-users=View users
|
||||
role_view-applications=View applications
|
||||
role_view-clients=View clients
|
||||
role_view-events=View events
|
||||
role_view-identity-providers=View identity providers
|
||||
role_manage-realm=Manage realm
|
||||
role_manage-users=Manage users
|
||||
role_manage-applications=Manage applications
|
||||
role_manage-identity-providers=Manage identity providers
|
||||
role_manage-clients=Manage clients
|
||||
role_manage-events=Manage events
|
||||
role_view-profile=View profile
|
||||
role_manage-account=Manage account
|
||||
role_manage-account-links=Manage account links
|
||||
role_read-token=Read token
|
||||
role_offline-access=Offline access
|
||||
client_account=Account
|
||||
client_account-console=Account Console
|
||||
client_security-admin-console=Security Admin Console
|
||||
client_admin-cli=Admin CLI
|
||||
client_realm-management=Realm Management
|
||||
client_broker=Broker
|
||||
|
||||
requiredFields=Required fields
|
||||
|
||||
invalidUserMessage=Invalid username or password.
|
||||
invalidUsernameMessage=Invalid username.
|
||||
invalidUsernameOrEmailMessage=Invalid username or email.
|
||||
invalidPasswordMessage=Invalid password.
|
||||
invalidEmailMessage=Invalid email address.
|
||||
accountDisabledMessage=Account is disabled, contact your administrator.
|
||||
accountTemporarilyDisabledMessage=Account is temporarily disabled; contact your administrator or retry later.
|
||||
expiredCodeMessage=Login timeout. Please sign in again.
|
||||
expiredActionMessage=Action expired. Please continue with login now.
|
||||
expiredActionTokenNoSessionMessage=Action expired.
|
||||
expiredActionTokenSessionExistsMessage=Action expired. Please start again.
|
||||
sessionLimitExceeded=There are too many sessions
|
||||
|
||||
missingFirstNameMessage=Please specify first name.
|
||||
missingLastNameMessage=Please specify last name.
|
||||
missingEmailMessage=Please specify email.
|
||||
missingUsernameMessage=Please specify username.
|
||||
missingPasswordMessage=Please specify password.
|
||||
missingTotpMessage=Please specify authenticator code.
|
||||
missingTotpDeviceNameMessage=Please specify device name.
|
||||
notMatchPasswordMessage=Passwords don''t match.
|
||||
|
||||
error-invalid-value=Invalid value.
|
||||
error-invalid-blank=Please specify value.
|
||||
error-empty=Please specify value.
|
||||
error-invalid-length=Length must be between {1} and {2}.
|
||||
error-invalid-length-too-short=Minimal length is {1}.
|
||||
error-invalid-length-too-long=Maximal length is {2}.
|
||||
error-invalid-email=Invalid email address.
|
||||
error-invalid-number=Invalid number.
|
||||
error-number-out-of-range=Number must be between {1} and {2}.
|
||||
error-number-out-of-range-too-small=Number must have minimal value of {1}.
|
||||
error-number-out-of-range-too-big=Number must have maximal value of {2}.
|
||||
error-pattern-no-match=Invalid value.
|
||||
error-invalid-uri=Invalid URL.
|
||||
error-invalid-uri-scheme=Invalid URL scheme.
|
||||
error-invalid-uri-fragment=Invalid URL fragment.
|
||||
error-user-attribute-required=Please specify this field.
|
||||
error-invalid-date=Invalid date.
|
||||
error-user-attribute-read-only=This field is read only.
|
||||
error-username-invalid-character=Value contains invalid character.
|
||||
error-person-name-invalid-character=Value contains invalid character.
|
||||
error-reset-otp-missing-id=Please choose an OTP configuration.
|
||||
|
||||
invalidPasswordExistingMessage=Invalid existing password.
|
||||
invalidPasswordBlacklistedMessage=Invalid password: password is blacklisted.
|
||||
invalidPasswordConfirmMessage=Password confirmation doesn''t match.
|
||||
invalidTotpMessage=Invalid authenticator code.
|
||||
|
||||
usernameExistsMessage=Username already exists.
|
||||
emailExistsMessage=Email already exists.
|
||||
|
||||
federatedIdentityExistsMessage=User with {0} {1} already exists. Please login to account management to link the account.
|
||||
federatedIdentityUnavailableMessage=User {0} authenticated with identity provider {1} does not exist. Please contact your administrator.
|
||||
federatedIdentityUnmatchedEssentialClaimMessage=The ID token issued by the identity provider does not match the configured essential claim. Please contact your administrator.
|
||||
|
||||
confirmLinkIdpTitle=Account already exists
|
||||
federatedIdentityConfirmLinkMessage=User with {0} {1} already exists. How do you want to continue?
|
||||
federatedIdentityConfirmReauthenticateMessage=Authenticate to link your account with {0}
|
||||
nestedFirstBrokerFlowMessage=The {0} user {1} is not linked to any known user.
|
||||
confirmLinkIdpReviewProfile=Review profile
|
||||
confirmLinkIdpContinue=Add to existing account
|
||||
|
||||
configureTotpMessage=You need to set up Mobile Authenticator to activate your account.
|
||||
configureBackupCodesMessage=You need to set up Backup Codes to activate your account.
|
||||
updateProfileMessage=You need to update your user profile to activate your account.
|
||||
updatePasswordMessage=You need to change your password to activate your account.
|
||||
updateEmailMessage=You need to update your email address to activate your account.
|
||||
resetPasswordMessage=You need to change your password.
|
||||
verifyEmailMessage=You need to verify your email address to activate your account.
|
||||
linkIdpMessage=You need to verify your email address to link your account with {0}.
|
||||
|
||||
emailSentMessage=You should receive an email shortly with further instructions.
|
||||
emailSendErrorMessage=Failed to send email, please try again later.
|
||||
|
||||
accountUpdatedMessage=Your account has been updated.
|
||||
accountPasswordUpdatedMessage=Your password has been updated.
|
||||
|
||||
delegationCompleteHeader=Login Successful
|
||||
delegationCompleteMessage=You may close this browser window and go back to your console application.
|
||||
delegationFailedHeader=Login Failed
|
||||
delegationFailedMessage=You may close this browser window and go back to your console application and try logging in again.
|
||||
|
||||
noAccessMessage=No access
|
||||
|
||||
invalidPasswordMinLengthMessage=Invalid password: minimum length {0}.
|
||||
invalidPasswordMaxLengthMessage=Invalid password: maximum length {0}.
|
||||
invalidPasswordMinDigitsMessage=Invalid password: must contain at least {0} numerical digits.
|
||||
invalidPasswordMinLowerCaseCharsMessage=Invalid password: must contain at least {0} lower case characters.
|
||||
invalidPasswordMinUpperCaseCharsMessage=Invalid password: must contain at least {0} upper case characters.
|
||||
invalidPasswordMinSpecialCharsMessage=Invalid password: must contain at least {0} special characters.
|
||||
invalidPasswordNotUsernameMessage=Invalid password: must not be equal to the username.
|
||||
invalidPasswordNotEmailMessage=Invalid password: must not be equal to the email.
|
||||
invalidPasswordRegexPatternMessage=Invalid password: fails to match regex pattern(s).
|
||||
invalidPasswordHistoryMessage=Invalid password: must not be equal to any of last {0} passwords.
|
||||
invalidPasswordGenericMessage=Invalid password: new password doesn''t match password policies.
|
||||
|
||||
failedToProcessResponseMessage=Failed to process response
|
||||
httpsRequiredMessage=HTTPS required
|
||||
realmNotEnabledMessage=Realm not enabled
|
||||
invalidRequestMessage=Invalid Request
|
||||
successLogout=You are logged out
|
||||
failedLogout=Logout failed
|
||||
unknownLoginRequesterMessage=Unknown login requester
|
||||
loginRequesterNotEnabledMessage=Login requester not enabled
|
||||
bearerOnlyMessage=Bearer-only applications are not allowed to initiate browser login
|
||||
standardFlowDisabledMessage=Client is not allowed to initiate browser login with given response_type. Standard flow is disabled for the client.
|
||||
implicitFlowDisabledMessage=Client is not allowed to initiate browser login with given response_type. Implicit flow is disabled for the client.
|
||||
invalidRedirectUriMessage=Invalid redirect uri
|
||||
unsupportedNameIdFormatMessage=Unsupported NameIDFormat
|
||||
invalidRequesterMessage=Invalid requester
|
||||
registrationNotAllowedMessage=Registration not allowed
|
||||
resetCredentialNotAllowedMessage=Reset Credential not allowed
|
||||
|
||||
permissionNotApprovedMessage=Permission not approved.
|
||||
noRelayStateInResponseMessage=No relay state in response from identity provider.
|
||||
insufficientPermissionMessage=Insufficient permissions to link identities.
|
||||
couldNotProceedWithAuthenticationRequestMessage=Could not proceed with authentication request to identity provider.
|
||||
couldNotObtainTokenMessage=Could not obtain token from identity provider.
|
||||
unexpectedErrorRetrievingTokenMessage=Unexpected error when retrieving token from identity provider.
|
||||
unexpectedErrorHandlingResponseMessage=Unexpected error when handling response from identity provider.
|
||||
identityProviderAuthenticationFailedMessage=Authentication failed. Could not authenticate with identity provider.
|
||||
couldNotSendAuthenticationRequestMessage=Could not send authentication request to identity provider.
|
||||
unexpectedErrorHandlingRequestMessage=Unexpected error when handling authentication request to identity provider.
|
||||
invalidAccessCodeMessage=Invalid access code.
|
||||
sessionNotActiveMessage=Session not active.
|
||||
invalidCodeMessage=An error occurred, please login again through your application.
|
||||
cookieNotFoundMessage=Cookie not found. Please make sure cookies are enabled in your browser.
|
||||
insufficientLevelOfAuthentication=The requested level of authentication has not been satisfied.
|
||||
identityProviderUnexpectedErrorMessage=Unexpected error when authenticating with identity provider
|
||||
identityProviderMissingStateMessage=Missing state parameter in response from identity provider.
|
||||
identityProviderInvalidResponseMessage=Invalid response from identity provider.
|
||||
identityProviderInvalidSignatureMessage=Invalid signature in response from identity provider.
|
||||
identityProviderNotFoundMessage=Could not find an identity provider with the identifier.
|
||||
identityProviderLinkSuccess=You successfully verified your email. Please go back to your original browser and continue there with the login.
|
||||
staleCodeMessage=This page is no longer valid, please go back to your application and sign in again
|
||||
realmSupportsNoCredentialsMessage=Realm does not support any credential type.
|
||||
credentialSetupRequired=Cannot login, credential setup required.
|
||||
identityProviderNotUniqueMessage=Realm supports multiple identity providers. Could not determine which identity provider should be used to authenticate with.
|
||||
emailVerifiedMessage=Your email address has been verified.
|
||||
staleEmailVerificationLink=The link you clicked is an old stale link and is no longer valid. Maybe you have already verified your email.
|
||||
identityProviderAlreadyLinkedMessage=Federated identity returned by {0} is already linked to another user.
|
||||
confirmAccountLinking=Confirm linking the account {0} of identity provider {1} with your account.
|
||||
confirmEmailAddressVerification=Confirm validity of e-mail address {0}.
|
||||
confirmExecutionOfActions=Perform the following action(s)
|
||||
|
||||
locale_ar=\u0639\u0631\u0628\u064A
|
||||
locale_ca=Catal\u00E0
|
||||
locale_cs=\u010Ce\u0161tina
|
||||
locale_da=Dansk
|
||||
locale_de=Deutsch
|
||||
locale_en=English
|
||||
locale_es=Espa\u00F1ol
|
||||
locale_fr=Fran\u00E7ais
|
||||
locale_hu=Magyar
|
||||
locale_it=Italiano
|
||||
locale_ja=\u65E5\u672C\u8A9E
|
||||
locale_lt=Lietuvi\u0173
|
||||
locale_nl=Nederlands
|
||||
locale_no=Norsk
|
||||
locale_pl=Polski
|
||||
locale_pt_BR=Portugu\u00EAs (Brasil)
|
||||
locale_pt-BR=Portugu\u00EAs (Brasil)
|
||||
locale_ru=\u0420\u0443\u0441\u0441\u043A\u0438\u0439
|
||||
locale_sk=Sloven\u010Dina
|
||||
locale_sv=Svenska
|
||||
locale_tr=T\u00FCrk\u00E7e
|
||||
locale_zh-CN=\u4E2D\u6587\u7B80\u4F53
|
||||
locale_fi=Suomi
|
||||
|
||||
backToApplication=« Back to Application
|
||||
missingParameterMessage=Missing parameters\: {0}
|
||||
clientNotFoundMessage=Client not found.
|
||||
clientDisabledMessage=Client disabled.
|
||||
invalidParameterMessage=Invalid parameter\: {0}
|
||||
alreadyLoggedIn=You are already logged in.
|
||||
differentUserAuthenticated=You are already authenticated as different user ''{0}'' in this session. Please sign out first.
|
||||
brokerLinkingSessionExpired=Requested broker account linking, but current session is no longer valid.
|
||||
proceedWithAction=» Click here to proceed
|
||||
acrNotFulfilled=Authentication requirements not fulfilled
|
||||
|
||||
requiredAction.CONFIGURE_TOTP=Configure OTP
|
||||
requiredAction.TERMS_AND_CONDITIONS=Terms and Conditions
|
||||
requiredAction.UPDATE_PASSWORD=Update Password
|
||||
requiredAction.UPDATE_PROFILE=Update Profile
|
||||
requiredAction.VERIFY_EMAIL=Verify Email
|
||||
requiredAction.CONFIGURE_RECOVERY_AUTHN_CODES=Generate Recovery Codes
|
||||
requiredAction.webauthn-register-passwordless=Webauthn Register Passwordless
|
||||
|
||||
invalidTokenRequiredActions=Required actions included in the link are not valid
|
||||
|
||||
doX509Login=You will be logged in as\:
|
||||
clientCertificate=X509 client certificate\:
|
||||
noCertificate=[No Certificate]
|
||||
|
||||
|
||||
pageNotFound=Page not found
|
||||
internalServerError=An internal server error has occurred
|
||||
|
||||
console-username=Username:
|
||||
console-password=Password:
|
||||
console-otp=One Time Password:
|
||||
console-new-password=New Password:
|
||||
console-confirm-password=Confirm Password:
|
||||
console-update-password=Update of your password is required.
|
||||
console-verify-email=You need to verify your email address. We sent an email to {0} that contains a verification code. Please enter this code into the input below.
|
||||
console-email-code=Email Code:
|
||||
console-accept-terms=Accept Terms? [y/n]:
|
||||
console-accept=y
|
||||
|
||||
# Openshift messages
|
||||
openshift.scope.user_info=User information
|
||||
openshift.scope.user_check-access=User access information
|
||||
openshift.scope.user_full=Full Access
|
||||
openshift.scope.list-projects=List projects
|
||||
|
||||
# SAML authentication
|
||||
saml.post-form.title=Authentication Redirect
|
||||
saml.post-form.message=Redirecting, please wait.
|
||||
saml.post-form.js-disabled=JavaScript is disabled. We strongly recommend to enable it. Click the button below to continue.
|
||||
saml.artifactResolutionServiceInvalidResponse=Unable to resolve artifact.
|
||||
|
||||
#authenticators
|
||||
otp-display-name=Authenticator Application
|
||||
otp-help-text=Enter a verification code from authenticator application.
|
||||
otp-reset-description=Which OTP configuration should be removed?
|
||||
password-display-name=Password
|
||||
password-help-text=Sign in by entering your password.
|
||||
auth-username-form-display-name=Username
|
||||
auth-username-form-help-text=Start sign in by entering your username
|
||||
auth-username-password-form-display-name=Username and password
|
||||
auth-username-password-form-help-text=Sign in by entering your username and password.
|
||||
|
||||
# Recovery Codes
|
||||
auth-recovery-authn-code-form-display-name=Recovery Authentication Code
|
||||
auth-recovery-authn-code-form-help-text=Enter a recovery authentication code from a previously generated list.
|
||||
auth-recovery-code-info-message=Enter the specified recovery code.
|
||||
auth-recovery-code-prompt=Recovery code #{0}
|
||||
auth-recovery-code-header=Login with a recovery authentication code
|
||||
recovery-codes-error-invalid=Invalid recovery authentication code
|
||||
recovery-code-config-header=Recovery Authentication Codes
|
||||
recovery-code-config-warning-title=These recovery codes won't appear again after leaving this page
|
||||
recovery-code-config-warning-message=Make sure to print, download, or copy them to a password manager and keep them save. Canceling this setup will remove these recovery codes from your account.
|
||||
recovery-codes-print=Print
|
||||
recovery-codes-download=Download
|
||||
recovery-codes-copy=Copy
|
||||
recovery-codes-copied=Copied
|
||||
recovery-codes-confirmation-message=I have saved these codes somewhere safe
|
||||
recovery-codes-action-complete=Complete setup
|
||||
recovery-codes-action-cancel=Cancel setup
|
||||
recovery-codes-download-file-header=Keep these recovery codes somewhere safe.
|
||||
recovery-codes-download-file-description=Recovery codes are single-use passcodes that allow you to sign in to your account if you do not have access to your authenticator.
|
||||
recovery-codes-download-file-date= These codes were generated on
|
||||
recovery-codes-label-default=Recovery codes
|
||||
|
||||
# WebAuthn
|
||||
webauthn-display-name=Security Key
|
||||
webauthn-help-text=Use your security key to sign in.
|
||||
webauthn-passwordless-display-name=Security Key
|
||||
webauthn-passwordless-help-text=Use your security key for passwordless sign in.
|
||||
webauthn-login-title=Security Key login
|
||||
webauthn-registration-title=Security Key Registration
|
||||
webauthn-available-authenticators=Available Security Keys
|
||||
webauthn-unsupported-browser-text=WebAuthn is not supported by this browser. Try another one or contact your administrator.
|
||||
webauthn-doAuthenticate=Sign in with Security Key
|
||||
webauthn-createdAt-label=Created
|
||||
|
||||
# WebAuthn Error
|
||||
webauthn-error-title=Security Key Error
|
||||
webauthn-error-registration=Failed to register your Security key.<br/> {0}
|
||||
webauthn-error-api-get=Failed to authenticate by the Security key.<br/> {0}
|
||||
webauthn-error-different-user=First authenticated user is not the one authenticated by the Security key.
|
||||
webauthn-error-auth-verification=Security key authentication result is invalid.<br/> {0}
|
||||
webauthn-error-register-verification=Security key registration result is invalid.<br/> {0}
|
||||
webauthn-error-user-not-found=Unknown user authenticated by the Security key.
|
||||
|
||||
# Identity provider
|
||||
identity-provider-redirector=Connect with another Identity Provider
|
||||
identity-provider-login-label=Or sign in with
|
||||
idp-email-verification-display-name=Email Verification
|
||||
idp-email-verification-help-text=Link your account by validating your email.
|
||||
idp-username-password-form-display-name=Username and password
|
||||
idp-username-password-form-help-text=Link your account by logging in.
|
||||
|
||||
finalDeletionConfirmation=If you delete your account, it cannot be restored. To keep your account, click Cancel.
|
||||
irreversibleAction=This action is irreversible
|
||||
deleteAccountConfirm=Delete account confirmation
|
||||
|
||||
deletingImplies=Deleting your account implies:
|
||||
errasingData=Erasing all your data
|
||||
loggingOutImmediately=Logging you out immediately
|
||||
accountUnusable=Any subsequent use of the application will not be possible with this account
|
||||
userDeletedSuccessfully=User deleted successfully
|
||||
|
||||
access-denied=Access denied
|
||||
access-denied-when-idp-auth=Access denied when authenticating with {0}
|
||||
|
||||
frontchannel-logout.title=Logging out
|
||||
frontchannel-logout.message=You are logging out from following apps
|
||||
logoutConfirmTitle=Logging out
|
||||
logoutConfirmHeader=Do you want to log out?
|
||||
doLogout=Logout
|
||||
|
||||
readOnlyUsernameMessage=You can''t update your username as it is read-only.
|
||||
609
keycloak_themes/edm/login/resources/css/login.css
Normal file
|
|
@ -0,0 +1,609 @@
|
|||
/* Patternfly CSS places a "bg-login.jpg" as the background on this ".login-pf" class.
|
||||
This clashes with the "keycloak-bg.png' background defined on the body below.
|
||||
Therefore the Patternfly background must be set to none. */
|
||||
.login-pf {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.login-pf body {
|
||||
background: url("../img/keycloak-bg.png") no-repeat center center fixed;
|
||||
background-size: cover;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
textarea.pf-c-form-control {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.pf-c-alert__title {
|
||||
font-size: var(--pf-global--FontSize--xs);
|
||||
}
|
||||
|
||||
p.instruction {
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.pf-c-button.pf-m-control {
|
||||
|
||||
}
|
||||
|
||||
h1#kc-page-title {
|
||||
margin-top: 10px;
|
||||
color: rgb(163, 163, 163);
|
||||
}
|
||||
|
||||
#kc-locale ul {
|
||||
background-color: var(--pf-global--BackgroundColor--100);
|
||||
display: none;
|
||||
top: 20px;
|
||||
min-width: 100px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#kc-locale-dropdown{
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#kc-locale-dropdown:hover ul {
|
||||
display:block;
|
||||
}
|
||||
|
||||
#kc-locale-dropdown a {
|
||||
color: var(--pf-global--Color--200);
|
||||
text-align: right;
|
||||
font-size: var(--pf-global--FontSize--sm);
|
||||
}
|
||||
|
||||
a#kc-current-locale-link::after {
|
||||
content: "\2c5";
|
||||
margin-left: var(--pf-global--spacer--xs)
|
||||
}
|
||||
|
||||
.login-pf .container {
|
||||
padding-top: 40px;
|
||||
}
|
||||
|
||||
.login-pf a:hover {
|
||||
color: #0099d3;
|
||||
}
|
||||
|
||||
#kc-logo {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div.kc-logo-text {
|
||||
background-image: url(../img/keycloak-logo-text.png);
|
||||
background-repeat: no-repeat;
|
||||
height: 63px;
|
||||
width: 300px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
div.kc-logo-text span {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#kc-header {
|
||||
color: #ededed;
|
||||
overflow: visible;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#kc-header-wrapper {
|
||||
font-size: 29px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 3px;
|
||||
line-height: 1.2em;
|
||||
padding: 20px 0px 0px 0px;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
#kc-content {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#kc-attempted-username {
|
||||
font-size: 20px;
|
||||
font-family: inherit;
|
||||
font-weight: normal;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
#kc-username {
|
||||
text-align: center;
|
||||
margin-bottom:-10px;
|
||||
}
|
||||
|
||||
#kc-webauthn-settings-form {
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
#kc-form-webauthn .select-auth-box-parent {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#kc-form-webauthn .select-auth-box-desc {
|
||||
color: var(--pf-global--palette--black-600);
|
||||
}
|
||||
|
||||
#kc-form-webauthn .select-auth-box-headline {
|
||||
color: var(--pf-global--Color--300);
|
||||
}
|
||||
|
||||
#kc-form-webauthn .select-auth-box-icon {
|
||||
flex: 0 0 3em;
|
||||
}
|
||||
|
||||
#kc-form-webauthn .select-auth-box-icon-properties {
|
||||
margin-top: 10px;
|
||||
font-size: 1.8em;
|
||||
}
|
||||
|
||||
#kc-form-webauthn .select-auth-box-icon-properties.unknown-transport-class {
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
#kc-form-webauthn .pf-l-stack__item {
|
||||
margin: -1px 0;
|
||||
}
|
||||
|
||||
#kc-content-wrapper {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
#kc-form-wrapper {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#kc-info {
|
||||
margin: 20px -40px -30px;
|
||||
}
|
||||
|
||||
#kc-info-wrapper {
|
||||
font-size: 13px;
|
||||
padding: 15px 35px;
|
||||
background-color: #F0F0F0;
|
||||
}
|
||||
|
||||
#kc-form-options span {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#kc-form-options .checkbox {
|
||||
margin-top: 0;
|
||||
color: #72767b;
|
||||
}
|
||||
|
||||
#kc-terms-text {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#kc-registration-terms-text {
|
||||
max-height: 100px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
#kc-registration {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* TOTP */
|
||||
|
||||
.subtitle {
|
||||
text-align: right;
|
||||
margin-top: 30px;
|
||||
color: #909090;
|
||||
}
|
||||
|
||||
.required {
|
||||
color: var(--pf-global--danger-color--200);
|
||||
}
|
||||
|
||||
ol#kc-totp-settings {
|
||||
margin: 0;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
ul#kc-totp-supported-apps {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#kc-totp-secret-qr-code {
|
||||
max-width:150px;
|
||||
max-height:150px;
|
||||
}
|
||||
|
||||
#kc-totp-secret-key {
|
||||
background-color: #fff;
|
||||
color: #333333;
|
||||
font-size: 16px;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
/* OAuth */
|
||||
|
||||
#kc-oauth h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#kc-oauth ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#kc-oauth ul li {
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||
font-size: 12px;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
#kc-oauth ul li:first-of-type {
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
#kc-oauth .kc-role {
|
||||
display: inline-block;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
/* Code */
|
||||
#kc-code textarea {
|
||||
width: 100%;
|
||||
height: 8em;
|
||||
}
|
||||
|
||||
/* Social */
|
||||
.kc-social-links {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.kc-social-links li {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.kc-social-provider-logo {
|
||||
font-size: 23px;
|
||||
width: 30px;
|
||||
height: 25px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.kc-social-gray {
|
||||
color: var(--pf-global--Color--200);
|
||||
}
|
||||
|
||||
.kc-social-item {
|
||||
margin-bottom: var(--pf-global--spacer--sm);
|
||||
font-size: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.kc-social-provider-name {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.kc-social-icon-text {
|
||||
left: -15px;
|
||||
}
|
||||
|
||||
.kc-social-grid {
|
||||
display:grid;
|
||||
grid-column-gap: 10px;
|
||||
grid-row-gap: 5px;
|
||||
grid-column-end: span 6;
|
||||
--pf-l-grid__item--GridColumnEnd: span 6;
|
||||
}
|
||||
|
||||
.kc-social-grid .kc-social-icon-text {
|
||||
left: -10px;
|
||||
}
|
||||
|
||||
.kc-login-tooltip {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.kc-social-section {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.kc-social-section hr{
|
||||
margin-bottom: 10px
|
||||
}
|
||||
|
||||
.kc-login-tooltip .kc-tooltip-text{
|
||||
top:-3px;
|
||||
left:160%;
|
||||
background-color: black;
|
||||
visibility: hidden;
|
||||
color: #fff;
|
||||
|
||||
min-width:130px;
|
||||
text-align: center;
|
||||
border-radius: 2px;
|
||||
box-shadow:0 1px 8px rgba(0,0,0,0.6);
|
||||
padding: 5px;
|
||||
|
||||
position: absolute;
|
||||
opacity:0;
|
||||
transition:opacity 0.5s;
|
||||
}
|
||||
|
||||
/* Show tooltip */
|
||||
.kc-login-tooltip:hover .kc-tooltip-text {
|
||||
visibility: visible;
|
||||
opacity:0.7;
|
||||
}
|
||||
|
||||
/* Arrow for tooltip */
|
||||
.kc-login-tooltip .kc-tooltip-text::after {
|
||||
content: " ";
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 100%;
|
||||
margin-top: -5px;
|
||||
border-width: 5px;
|
||||
border-style: solid;
|
||||
border-color: transparent black transparent transparent;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#kc-container-wrapper {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.login-pf .container {
|
||||
padding-right: 80px;
|
||||
}
|
||||
|
||||
#kc-locale {
|
||||
position: relative;
|
||||
text-align: right;
|
||||
z-index: 9999;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
|
||||
.login-pf body {
|
||||
background: white;
|
||||
}
|
||||
|
||||
#kc-header {
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
float: none;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#kc-header-wrapper {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
padding: 20px 0 0 0;
|
||||
color: #72767b;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
div.kc-logo-text {
|
||||
margin: 0;
|
||||
width: 150px;
|
||||
height: 32px;
|
||||
background-size: 100%;
|
||||
}
|
||||
|
||||
#kc-form {
|
||||
float: none;
|
||||
}
|
||||
|
||||
#kc-info-wrapper {
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.login-pf .container {
|
||||
padding-top: 15px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
#kc-locale {
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
text-align: right;
|
||||
z-index: 9999;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-height: 646px) {
|
||||
#kc-container-wrapper {
|
||||
bottom: 12%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-height: 645px) {
|
||||
#kc-container-wrapper {
|
||||
padding-top: 50px;
|
||||
top: 20%;
|
||||
}
|
||||
}
|
||||
|
||||
.card-pf form.form-actions .btn {
|
||||
float: right;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
#kc-form-buttons {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.login-pf-page .login-pf-brand {
|
||||
margin-top: 20px;
|
||||
max-width: 360px;
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
.select-auth-box-arrow{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 2rem;
|
||||
}
|
||||
|
||||
.select-auth-box-icon{
|
||||
display: flex;
|
||||
flex: 0 0 2em;
|
||||
justify-content: center;
|
||||
margin-right: 1rem;
|
||||
margin-left: 3rem;
|
||||
}
|
||||
|
||||
.select-auth-box-parent{
|
||||
border-top: 1px solid var(--pf-global--palette--black-200);
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.select-auth-box-parent:hover{
|
||||
background-color: #f7f8f8;
|
||||
}
|
||||
|
||||
.select-auth-container {
|
||||
padding-bottom: 0px !important;
|
||||
}
|
||||
|
||||
.select-auth-box-headline {
|
||||
font-size: var(--pf-global--FontSize--md);
|
||||
color: var(--pf-global--primary-color--100);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.select-auth-box-desc {
|
||||
font-size: var(--pf-global--FontSize--sm);
|
||||
}
|
||||
|
||||
.select-auth-box-paragraph {
|
||||
text-align: center;
|
||||
font-size: var(--pf-global--FontSize--md);
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.card-pf {
|
||||
margin: 0 auto;
|
||||
box-shadow: var(--pf-global--BoxShadow--lg);
|
||||
padding: 0 20px;
|
||||
max-width: 500px;
|
||||
border-radius: 15px;
|
||||
|
||||
}
|
||||
|
||||
/*phone*/
|
||||
@media (max-width: 100px) {
|
||||
.login-pf-page .card-pf {
|
||||
max-width: 500px;
|
||||
padding: 0 20px;
|
||||
border-top: 4px solid;
|
||||
box-shadow: var(--pf-global--BoxShadow--lg);
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
border-radius: 25px;
|
||||
border-color: var(--pf-global--primary-color--100);
|
||||
}
|
||||
|
||||
.kc-social-grid {
|
||||
grid-column-end: 12;
|
||||
--pf-l-grid__item--GridColumnEnd: span 12;
|
||||
}
|
||||
|
||||
.kc-social-grid .kc-social-icon-text {
|
||||
left: -15px;
|
||||
}
|
||||
}
|
||||
|
||||
.login-pf-page .login-pf-signup {
|
||||
font-size: 15px;
|
||||
color: #72767b;
|
||||
}
|
||||
#kc-content-wrapper .row {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.login-pf-page.login-pf-page-accounts {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.login-pf-page .btn-primary {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.login-pf-page .list-view-pf .list-group-item {
|
||||
border-bottom: 1px solid #ededed;
|
||||
}
|
||||
|
||||
.login-pf-page .list-view-pf-description {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#kc-form-login div.form-group:last-of-type,
|
||||
#kc-register-form div.form-group:last-of-type,
|
||||
#kc-update-profile-form div.form-group:last-of-type,
|
||||
#kc-update-email-form div.form-group:last-of-type{
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.no-bottom-margin {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#kc-back {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
/* Recovery codes */
|
||||
.kc-recovery-codes-warning {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
.kc-recovery-codes-warning .pf-c-alert__description p {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
.kc-recovery-codes-list {
|
||||
list-style: none;
|
||||
columns: 2;
|
||||
margin: 16px 0;
|
||||
padding: 16px 16px 8px 16px;
|
||||
border: 1px solid #D2D2D2;
|
||||
}
|
||||
.kc-recovery-codes-list li {
|
||||
margin-bottom: 8px;
|
||||
font-size: 11px;
|
||||
}
|
||||
.kc-recovery-codes-list li span {
|
||||
color: #6A6E73;
|
||||
width: 16px;
|
||||
text-align: right;
|
||||
display: inline-block;
|
||||
margin-right: 1px;
|
||||
}
|
||||
|
||||
.kc-recovery-codes-actions {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
.kc-recovery-codes-actions button {
|
||||
padding-left: 0;
|
||||
}
|
||||
.kc-recovery-codes-actions button i {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.kc-recovery-codes-confirmation {
|
||||
align-items: baseline;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
/* End Recovery codes */
|
||||
BIN
keycloak_themes/edm/login/resources/img/edm-logo-textasdasd.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 513 B |
BIN
keycloak_themes/edm/login/resources/img/feedback-error-sign.png
Normal file
|
After Width: | Height: | Size: 343 B |
|
After Width: | Height: | Size: 678 B |
|
After Width: | Height: | Size: 410 B |
|
After Width: | Height: | Size: 513 B |
|
After Width: | Height: | Size: 646 B |
BIN
keycloak_themes/edm/login/resources/img/grey1.png
Normal file
|
After Width: | Height: | Size: 257 KiB |
BIN
keycloak_themes/edm/login/resources/img/grey2.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
keycloak_themes/edm/login/resources/img/keycloak-bg.png
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
keycloak_themes/edm/login/resources/img/keycloak-logo-text.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
keycloak_themes/edm/login/resources/img/keycloak-logo.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
keycloak_themes/edm/login/resources/img/logo-bangkok.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
keycloak_themes/edm/login/resources/img/logo-bangkok2.png
Normal file
|
After Width: | Height: | Size: 219 KiB |
BIN
keycloak_themes/edm/login/resources/img/logo-bangkok3.png
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
keycloak_themes/edm/login/resources/img/logo-bangkok4.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
keycloak_themes/edm/login/resources/img/logo.png
Normal file
|
After Width: | Height: | Size: 4.2 MiB |
516
keycloak_themes/edm2/login/messages/messages_en.properties
Normal file
|
|
@ -0,0 +1,516 @@
|
|||
doLogIn=LOGIN
|
||||
doRegister=Register
|
||||
doCancel=Cancel
|
||||
doSubmit=Submit
|
||||
doBack=Back
|
||||
doYes=Yes
|
||||
doNo=No
|
||||
doContinue=Continue
|
||||
doIgnore=Ignore
|
||||
doAccept=Accept
|
||||
doDecline=Decline
|
||||
doForgotPassword=Forgot Password?
|
||||
doClickHere=Click here
|
||||
doImpersonate=Impersonate
|
||||
doTryAgain=Try again
|
||||
doTryAnotherWay=Try Another Way
|
||||
doConfirmDelete=Confirm deletion
|
||||
errorDeletingAccount=Error happened while deleting account
|
||||
deletingAccountForbidden=You do not have enough permissions to delete your own account, contact admin.
|
||||
kerberosNotConfigured=Kerberos Not Configured
|
||||
kerberosNotConfiguredTitle=Kerberos Not Configured
|
||||
bypassKerberosDetail=Either you are not logged in by Kerberos or your browser is not set up for Kerberos login. Please click continue to login in through other means
|
||||
kerberosNotSetUp=Kerberos is not set up. You cannot login.
|
||||
registerTitle=Register
|
||||
loginAccountTitle=Enterprise Document Management (EDM)
|
||||
loginTitle=Sign in to {0}
|
||||
loginTitleHtml={0}
|
||||
impersonateTitle={0} Impersonate User
|
||||
impersonateTitleHtml=<strong>{0}</strong> Impersonate User
|
||||
realmChoice=Realm
|
||||
unknownUser=Unknown user
|
||||
loginTotpTitle=Mobile Authenticator Setup
|
||||
loginProfileTitle=Update Account Information
|
||||
loginIdpReviewProfileTitle=Update Account Information
|
||||
loginTimeout=Your login attempt timed out. Login will start from the beginning.
|
||||
reauthenticate=Please re-authenticate to continue
|
||||
oauthGrantTitle=Grant Access to {0}
|
||||
oauthGrantTitleHtml={0}
|
||||
oauthGrantInformation=Make sure you trust {0} by learning how {0} will handle your data.
|
||||
oauthGrantReview=You could review the
|
||||
oauthGrantTos=terms of service.
|
||||
oauthGrantPolicy=privacy policy.
|
||||
errorTitle=We are sorry...
|
||||
errorTitleHtml=We are <strong>sorry</strong> ...
|
||||
emailVerifyTitle=Email verification
|
||||
emailForgotTitle=Forgot Your Password?
|
||||
updateEmailTitle=Update email
|
||||
emailUpdateConfirmationSentTitle=Confirmation email sent
|
||||
emailUpdateConfirmationSent=A confirmation email has been sent to {0}. You must follow the instructions of the former to complete the email update.
|
||||
emailUpdatedTitle=Email updated
|
||||
emailUpdated=The account email has been successfully updated to {0}.
|
||||
updatePasswordTitle=Update password
|
||||
codeSuccessTitle=Success code
|
||||
codeErrorTitle=Error code\: {0}
|
||||
displayUnsupported=Requested display type unsupported
|
||||
browserRequired=Browser required to login
|
||||
browserContinue=Browser required to complete login
|
||||
browserContinuePrompt=Open browser and continue login? [y/n]:
|
||||
browserContinueAnswer=y
|
||||
|
||||
# Transports
|
||||
usb=USB
|
||||
nfc=NFC
|
||||
bluetooth=Bluetooth
|
||||
internal=Internal
|
||||
unknown=Unknown
|
||||
|
||||
termsTitle=Terms and Conditions
|
||||
termsText=<p>Terms and conditions to be defined</p>
|
||||
termsPlainText=Terms and conditions to be defined.
|
||||
termsAcceptanceRequired=You must agree to our terms and conditions.
|
||||
acceptTerms=I agree to the terms and conditions
|
||||
|
||||
recaptchaFailed=Invalid Recaptcha
|
||||
recaptchaNotConfigured=Recaptcha is required, but not configured
|
||||
consentDenied=Consent denied.
|
||||
|
||||
noAccount=New user?
|
||||
username=Username
|
||||
usernameOrEmail=Username
|
||||
firstName=First name
|
||||
givenName=Given name
|
||||
fullName=Full name
|
||||
lastName=Last name
|
||||
familyName=Family name
|
||||
email=Email
|
||||
password=Password
|
||||
passwordConfirm=Confirm password
|
||||
passwordNew=New Password
|
||||
passwordNewConfirm=New Password confirmation
|
||||
rememberMe=Remember me
|
||||
authenticatorCode=One-time code
|
||||
address=Address
|
||||
street=Street
|
||||
locality=City or Locality
|
||||
region=State, Province, or Region
|
||||
postal_code=Zip or Postal code
|
||||
country=Country
|
||||
emailVerified=Email verified
|
||||
website=Web page
|
||||
phoneNumber=Phone number
|
||||
phoneNumberVerified=Phone number verified
|
||||
gender=Gender
|
||||
birthday=Birthdate
|
||||
zoneinfo=Time zone
|
||||
gssDelegationCredential=GSS Delegation Credential
|
||||
logoutOtherSessions=Sign out from other devices
|
||||
|
||||
profileScopeConsentText=User profile
|
||||
emailScopeConsentText=Email address
|
||||
addressScopeConsentText=Address
|
||||
phoneScopeConsentText=Phone number
|
||||
offlineAccessScopeConsentText=Offline Access
|
||||
samlRoleListScopeConsentText=My Roles
|
||||
rolesScopeConsentText=User roles
|
||||
|
||||
restartLoginTooltip=Restart login
|
||||
|
||||
loginTotpIntro=You need to set up a One Time Password generator to access this account
|
||||
loginTotpStep1=Install one of the following applications on your mobile:
|
||||
loginTotpStep2=Open the application and scan the barcode:
|
||||
loginTotpStep3=Enter the one-time code provided by the application and click Submit to finish the setup.
|
||||
loginTotpStep3DeviceName=Provide a Device Name to help you manage your OTP devices.
|
||||
loginTotpManualStep2=Open the application and enter the key:
|
||||
loginTotpManualStep3=Use the following configuration values if the application allows setting them:
|
||||
loginTotpUnableToScan=Unable to scan?
|
||||
loginTotpScanBarcode=Scan barcode?
|
||||
loginCredential=Credential
|
||||
loginOtpOneTime=One-time code
|
||||
loginTotpType=Type
|
||||
loginTotpAlgorithm=Algorithm
|
||||
loginTotpDigits=Digits
|
||||
loginTotpInterval=Interval
|
||||
loginTotpCounter=Counter
|
||||
loginTotpDeviceName=Device Name
|
||||
|
||||
loginTotp.totp=Time-based
|
||||
loginTotp.hotp=Counter-based
|
||||
|
||||
totpAppFreeOTPName=FreeOTP
|
||||
totpAppGoogleName=Google Authenticator
|
||||
totpAppMicrosoftAuthenticatorName=Microsoft Authenticator
|
||||
|
||||
loginChooseAuthenticator=Select login method
|
||||
|
||||
oauthGrantRequest=Do you grant these access privileges?
|
||||
inResource=in
|
||||
|
||||
oauth2DeviceVerificationTitle=Device Login
|
||||
verifyOAuth2DeviceUserCode=Enter the code provided by your device and click Submit
|
||||
oauth2DeviceInvalidUserCodeMessage=Invalid code, please try again.
|
||||
oauth2DeviceExpiredUserCodeMessage=The code has expired. Please go back to your device and try connecting again.
|
||||
oauth2DeviceVerificationCompleteHeader=Device Login Successful
|
||||
oauth2DeviceVerificationCompleteMessage=You may close this browser window and go back to your device.
|
||||
oauth2DeviceVerificationFailedHeader=Device Login Failed
|
||||
oauth2DeviceVerificationFailedMessage=You may close this browser window and go back to your device and try connecting again.
|
||||
oauth2DeviceConsentDeniedMessage=Consent denied for connecting the device.
|
||||
oauth2DeviceAuthorizationGrantDisabledMessage=Client is not allowed to initiate OAuth 2.0 Device Authorization Grant. The flow is disabled for the client.
|
||||
|
||||
emailVerifyInstruction1=An email with instructions to verify your email address has been sent to your address {0}.
|
||||
emailVerifyInstruction2=Haven''t received a verification code in your email?
|
||||
emailVerifyInstruction3=to re-send the email.
|
||||
|
||||
emailLinkIdpTitle=Link {0}
|
||||
emailLinkIdp1=An email with instructions to link {0} account {1} with your {2} account has been sent to you.
|
||||
emailLinkIdp2=Haven''t received a verification code in your email?
|
||||
emailLinkIdp3=to re-send the email.
|
||||
emailLinkIdp4=If you already verified the email in different browser
|
||||
emailLinkIdp5=to continue.
|
||||
|
||||
backToLogin=« Back to Login
|
||||
|
||||
emailInstruction=Enter your username or email address and we will send you instructions on how to create a new password.
|
||||
emailInstructionUsername=Enter your username and we will send you instructions on how to create a new password.
|
||||
|
||||
copyCodeInstruction=Please copy this code and paste it into your application:
|
||||
|
||||
pageExpiredTitle=Page has expired
|
||||
pageExpiredMsg1=To restart the login process
|
||||
pageExpiredMsg2=To continue the login process
|
||||
|
||||
personalInfo=Personal Info:
|
||||
role_admin=Admin
|
||||
role_realm-admin=Realm Admin
|
||||
role_create-realm=Create realm
|
||||
role_create-client=Create client
|
||||
role_view-realm=View realm
|
||||
role_view-users=View users
|
||||
role_view-applications=View applications
|
||||
role_view-clients=View clients
|
||||
role_view-events=View events
|
||||
role_view-identity-providers=View identity providers
|
||||
role_manage-realm=Manage realm
|
||||
role_manage-users=Manage users
|
||||
role_manage-applications=Manage applications
|
||||
role_manage-identity-providers=Manage identity providers
|
||||
role_manage-clients=Manage clients
|
||||
role_manage-events=Manage events
|
||||
role_view-profile=View profile
|
||||
role_manage-account=Manage account
|
||||
role_manage-account-links=Manage account links
|
||||
role_read-token=Read token
|
||||
role_offline-access=Offline access
|
||||
client_account=Account
|
||||
client_account-console=Account Console
|
||||
client_security-admin-console=Security Admin Console
|
||||
client_admin-cli=Admin CLI
|
||||
client_realm-management=Realm Management
|
||||
client_broker=Broker
|
||||
|
||||
requiredFields=Required fields
|
||||
|
||||
invalidUserMessage=Invalid username or password.
|
||||
invalidUsernameMessage=Invalid username.
|
||||
invalidUsernameOrEmailMessage=Invalid username or email.
|
||||
invalidPasswordMessage=Invalid password.
|
||||
invalidEmailMessage=Invalid email address.
|
||||
accountDisabledMessage=Account is disabled, contact your administrator.
|
||||
accountTemporarilyDisabledMessage=Account is temporarily disabled; contact your administrator or retry later.
|
||||
expiredCodeMessage=Login timeout. Please sign in again.
|
||||
expiredActionMessage=Action expired. Please continue with login now.
|
||||
expiredActionTokenNoSessionMessage=Action expired.
|
||||
expiredActionTokenSessionExistsMessage=Action expired. Please start again.
|
||||
sessionLimitExceeded=There are too many sessions
|
||||
|
||||
missingFirstNameMessage=Please specify first name.
|
||||
missingLastNameMessage=Please specify last name.
|
||||
missingEmailMessage=Please specify email.
|
||||
missingUsernameMessage=Please specify username.
|
||||
missingPasswordMessage=Please specify password.
|
||||
missingTotpMessage=Please specify authenticator code.
|
||||
missingTotpDeviceNameMessage=Please specify device name.
|
||||
notMatchPasswordMessage=Passwords don''t match.
|
||||
|
||||
error-invalid-value=Invalid value.
|
||||
error-invalid-blank=Please specify value.
|
||||
error-empty=Please specify value.
|
||||
error-invalid-length=Length must be between {1} and {2}.
|
||||
error-invalid-length-too-short=Minimal length is {1}.
|
||||
error-invalid-length-too-long=Maximal length is {2}.
|
||||
error-invalid-email=Invalid email address.
|
||||
error-invalid-number=Invalid number.
|
||||
error-number-out-of-range=Number must be between {1} and {2}.
|
||||
error-number-out-of-range-too-small=Number must have minimal value of {1}.
|
||||
error-number-out-of-range-too-big=Number must have maximal value of {2}.
|
||||
error-pattern-no-match=Invalid value.
|
||||
error-invalid-uri=Invalid URL.
|
||||
error-invalid-uri-scheme=Invalid URL scheme.
|
||||
error-invalid-uri-fragment=Invalid URL fragment.
|
||||
error-user-attribute-required=Please specify this field.
|
||||
error-invalid-date=Invalid date.
|
||||
error-user-attribute-read-only=This field is read only.
|
||||
error-username-invalid-character=Value contains invalid character.
|
||||
error-person-name-invalid-character=Value contains invalid character.
|
||||
error-reset-otp-missing-id=Please choose an OTP configuration.
|
||||
|
||||
invalidPasswordExistingMessage=Invalid existing password.
|
||||
invalidPasswordBlacklistedMessage=Invalid password: password is blacklisted.
|
||||
invalidPasswordConfirmMessage=Password confirmation doesn''t match.
|
||||
invalidTotpMessage=Invalid authenticator code.
|
||||
|
||||
usernameExistsMessage=Username already exists.
|
||||
emailExistsMessage=Email already exists.
|
||||
|
||||
federatedIdentityExistsMessage=User with {0} {1} already exists. Please login to account management to link the account.
|
||||
federatedIdentityUnavailableMessage=User {0} authenticated with identity provider {1} does not exist. Please contact your administrator.
|
||||
federatedIdentityUnmatchedEssentialClaimMessage=The ID token issued by the identity provider does not match the configured essential claim. Please contact your administrator.
|
||||
|
||||
confirmLinkIdpTitle=Account already exists
|
||||
federatedIdentityConfirmLinkMessage=User with {0} {1} already exists. How do you want to continue?
|
||||
federatedIdentityConfirmReauthenticateMessage=Authenticate to link your account with {0}
|
||||
nestedFirstBrokerFlowMessage=The {0} user {1} is not linked to any known user.
|
||||
confirmLinkIdpReviewProfile=Review profile
|
||||
confirmLinkIdpContinue=Add to existing account
|
||||
|
||||
configureTotpMessage=You need to set up Mobile Authenticator to activate your account.
|
||||
configureBackupCodesMessage=You need to set up Backup Codes to activate your account.
|
||||
updateProfileMessage=You need to update your user profile to activate your account.
|
||||
updatePasswordMessage=You need to change your password to activate your account.
|
||||
updateEmailMessage=You need to update your email address to activate your account.
|
||||
resetPasswordMessage=You need to change your password.
|
||||
verifyEmailMessage=You need to verify your email address to activate your account.
|
||||
linkIdpMessage=You need to verify your email address to link your account with {0}.
|
||||
|
||||
emailSentMessage=You should receive an email shortly with further instructions.
|
||||
emailSendErrorMessage=Failed to send email, please try again later.
|
||||
|
||||
accountUpdatedMessage=Your account has been updated.
|
||||
accountPasswordUpdatedMessage=Your password has been updated.
|
||||
|
||||
delegationCompleteHeader=Login Successful
|
||||
delegationCompleteMessage=You may close this browser window and go back to your console application.
|
||||
delegationFailedHeader=Login Failed
|
||||
delegationFailedMessage=You may close this browser window and go back to your console application and try logging in again.
|
||||
|
||||
noAccessMessage=No access
|
||||
|
||||
invalidPasswordMinLengthMessage=Invalid password: minimum length {0}.
|
||||
invalidPasswordMaxLengthMessage=Invalid password: maximum length {0}.
|
||||
invalidPasswordMinDigitsMessage=Invalid password: must contain at least {0} numerical digits.
|
||||
invalidPasswordMinLowerCaseCharsMessage=Invalid password: must contain at least {0} lower case characters.
|
||||
invalidPasswordMinUpperCaseCharsMessage=Invalid password: must contain at least {0} upper case characters.
|
||||
invalidPasswordMinSpecialCharsMessage=Invalid password: must contain at least {0} special characters.
|
||||
invalidPasswordNotUsernameMessage=Invalid password: must not be equal to the username.
|
||||
invalidPasswordNotEmailMessage=Invalid password: must not be equal to the email.
|
||||
invalidPasswordRegexPatternMessage=Invalid password: fails to match regex pattern(s).
|
||||
invalidPasswordHistoryMessage=Invalid password: must not be equal to any of last {0} passwords.
|
||||
invalidPasswordGenericMessage=Invalid password: new password doesn''t match password policies.
|
||||
|
||||
failedToProcessResponseMessage=Failed to process response
|
||||
httpsRequiredMessage=HTTPS required
|
||||
realmNotEnabledMessage=Realm not enabled
|
||||
invalidRequestMessage=Invalid Request
|
||||
successLogout=You are logged out
|
||||
failedLogout=Logout failed
|
||||
unknownLoginRequesterMessage=Unknown login requester
|
||||
loginRequesterNotEnabledMessage=Login requester not enabled
|
||||
bearerOnlyMessage=Bearer-only applications are not allowed to initiate browser login
|
||||
standardFlowDisabledMessage=Client is not allowed to initiate browser login with given response_type. Standard flow is disabled for the client.
|
||||
implicitFlowDisabledMessage=Client is not allowed to initiate browser login with given response_type. Implicit flow is disabled for the client.
|
||||
invalidRedirectUriMessage=Invalid redirect uri
|
||||
unsupportedNameIdFormatMessage=Unsupported NameIDFormat
|
||||
invalidRequesterMessage=Invalid requester
|
||||
registrationNotAllowedMessage=Registration not allowed
|
||||
resetCredentialNotAllowedMessage=Reset Credential not allowed
|
||||
|
||||
permissionNotApprovedMessage=Permission not approved.
|
||||
noRelayStateInResponseMessage=No relay state in response from identity provider.
|
||||
insufficientPermissionMessage=Insufficient permissions to link identities.
|
||||
couldNotProceedWithAuthenticationRequestMessage=Could not proceed with authentication request to identity provider.
|
||||
couldNotObtainTokenMessage=Could not obtain token from identity provider.
|
||||
unexpectedErrorRetrievingTokenMessage=Unexpected error when retrieving token from identity provider.
|
||||
unexpectedErrorHandlingResponseMessage=Unexpected error when handling response from identity provider.
|
||||
identityProviderAuthenticationFailedMessage=Authentication failed. Could not authenticate with identity provider.
|
||||
couldNotSendAuthenticationRequestMessage=Could not send authentication request to identity provider.
|
||||
unexpectedErrorHandlingRequestMessage=Unexpected error when handling authentication request to identity provider.
|
||||
invalidAccessCodeMessage=Invalid access code.
|
||||
sessionNotActiveMessage=Session not active.
|
||||
invalidCodeMessage=An error occurred, please login again through your application.
|
||||
cookieNotFoundMessage=Cookie not found. Please make sure cookies are enabled in your browser.
|
||||
insufficientLevelOfAuthentication=The requested level of authentication has not been satisfied.
|
||||
identityProviderUnexpectedErrorMessage=Unexpected error when authenticating with identity provider
|
||||
identityProviderMissingStateMessage=Missing state parameter in response from identity provider.
|
||||
identityProviderInvalidResponseMessage=Invalid response from identity provider.
|
||||
identityProviderInvalidSignatureMessage=Invalid signature in response from identity provider.
|
||||
identityProviderNotFoundMessage=Could not find an identity provider with the identifier.
|
||||
identityProviderLinkSuccess=You successfully verified your email. Please go back to your original browser and continue there with the login.
|
||||
staleCodeMessage=This page is no longer valid, please go back to your application and sign in again
|
||||
realmSupportsNoCredentialsMessage=Realm does not support any credential type.
|
||||
credentialSetupRequired=Cannot login, credential setup required.
|
||||
identityProviderNotUniqueMessage=Realm supports multiple identity providers. Could not determine which identity provider should be used to authenticate with.
|
||||
emailVerifiedMessage=Your email address has been verified.
|
||||
staleEmailVerificationLink=The link you clicked is an old stale link and is no longer valid. Maybe you have already verified your email.
|
||||
identityProviderAlreadyLinkedMessage=Federated identity returned by {0} is already linked to another user.
|
||||
confirmAccountLinking=Confirm linking the account {0} of identity provider {1} with your account.
|
||||
confirmEmailAddressVerification=Confirm validity of e-mail address {0}.
|
||||
confirmExecutionOfActions=Perform the following action(s)
|
||||
|
||||
locale_ar=\u0639\u0631\u0628\u064A
|
||||
locale_ca=Catal\u00E0
|
||||
locale_cs=\u010Ce\u0161tina
|
||||
locale_da=Dansk
|
||||
locale_de=Deutsch
|
||||
locale_en=English
|
||||
locale_es=Espa\u00F1ol
|
||||
locale_fr=Fran\u00E7ais
|
||||
locale_hu=Magyar
|
||||
locale_it=Italiano
|
||||
locale_ja=\u65E5\u672C\u8A9E
|
||||
locale_lt=Lietuvi\u0173
|
||||
locale_nl=Nederlands
|
||||
locale_no=Norsk
|
||||
locale_pl=Polski
|
||||
locale_pt_BR=Portugu\u00EAs (Brasil)
|
||||
locale_pt-BR=Portugu\u00EAs (Brasil)
|
||||
locale_ru=\u0420\u0443\u0441\u0441\u043A\u0438\u0439
|
||||
locale_sk=Sloven\u010Dina
|
||||
locale_sv=Svenska
|
||||
locale_tr=T\u00FCrk\u00E7e
|
||||
locale_zh-CN=\u4E2D\u6587\u7B80\u4F53
|
||||
locale_fi=Suomi
|
||||
|
||||
backToApplication=« Back to Application
|
||||
missingParameterMessage=Missing parameters\: {0}
|
||||
clientNotFoundMessage=Client not found.
|
||||
clientDisabledMessage=Client disabled.
|
||||
invalidParameterMessage=Invalid parameter\: {0}
|
||||
alreadyLoggedIn=You are already logged in.
|
||||
differentUserAuthenticated=You are already authenticated as different user ''{0}'' in this session. Please sign out first.
|
||||
brokerLinkingSessionExpired=Requested broker account linking, but current session is no longer valid.
|
||||
proceedWithAction=» Click here to proceed
|
||||
acrNotFulfilled=Authentication requirements not fulfilled
|
||||
|
||||
requiredAction.CONFIGURE_TOTP=Configure OTP
|
||||
requiredAction.TERMS_AND_CONDITIONS=Terms and Conditions
|
||||
requiredAction.UPDATE_PASSWORD=Update Password
|
||||
requiredAction.UPDATE_PROFILE=Update Profile
|
||||
requiredAction.VERIFY_EMAIL=Verify Email
|
||||
requiredAction.CONFIGURE_RECOVERY_AUTHN_CODES=Generate Recovery Codes
|
||||
requiredAction.webauthn-register-passwordless=Webauthn Register Passwordless
|
||||
|
||||
invalidTokenRequiredActions=Required actions included in the link are not valid
|
||||
|
||||
doX509Login=You will be logged in as\:
|
||||
clientCertificate=X509 client certificate\:
|
||||
noCertificate=[No Certificate]
|
||||
|
||||
|
||||
pageNotFound=Page not found
|
||||
internalServerError=An internal server error has occurred
|
||||
|
||||
console-username=Username:
|
||||
console-password=Password:
|
||||
console-otp=One Time Password:
|
||||
console-new-password=New Password:
|
||||
console-confirm-password=Confirm Password:
|
||||
console-update-password=Update of your password is required.
|
||||
console-verify-email=You need to verify your email address. We sent an email to {0} that contains a verification code. Please enter this code into the input below.
|
||||
console-email-code=Email Code:
|
||||
console-accept-terms=Accept Terms? [y/n]:
|
||||
console-accept=y
|
||||
|
||||
# Openshift messages
|
||||
openshift.scope.user_info=User information
|
||||
openshift.scope.user_check-access=User access information
|
||||
openshift.scope.user_full=Full Access
|
||||
openshift.scope.list-projects=List projects
|
||||
|
||||
# SAML authentication
|
||||
saml.post-form.title=Authentication Redirect
|
||||
saml.post-form.message=Redirecting, please wait.
|
||||
saml.post-form.js-disabled=JavaScript is disabled. We strongly recommend to enable it. Click the button below to continue.
|
||||
saml.artifactResolutionServiceInvalidResponse=Unable to resolve artifact.
|
||||
|
||||
#authenticators
|
||||
otp-display-name=Authenticator Application
|
||||
otp-help-text=Enter a verification code from authenticator application.
|
||||
otp-reset-description=Which OTP configuration should be removed?
|
||||
password-display-name=Password
|
||||
password-help-text=Sign in by entering your password.
|
||||
auth-username-form-display-name=Username
|
||||
auth-username-form-help-text=Start sign in by entering your username
|
||||
auth-username-password-form-display-name=Username and password
|
||||
auth-username-password-form-help-text=Sign in by entering your username and password.
|
||||
|
||||
# Recovery Codes
|
||||
auth-recovery-authn-code-form-display-name=Recovery Authentication Code
|
||||
auth-recovery-authn-code-form-help-text=Enter a recovery authentication code from a previously generated list.
|
||||
auth-recovery-code-info-message=Enter the specified recovery code.
|
||||
auth-recovery-code-prompt=Recovery code #{0}
|
||||
auth-recovery-code-header=Login with a recovery authentication code
|
||||
recovery-codes-error-invalid=Invalid recovery authentication code
|
||||
recovery-code-config-header=Recovery Authentication Codes
|
||||
recovery-code-config-warning-title=These recovery codes won't appear again after leaving this page
|
||||
recovery-code-config-warning-message=Make sure to print, download, or copy them to a password manager and keep them save. Canceling this setup will remove these recovery codes from your account.
|
||||
recovery-codes-print=Print
|
||||
recovery-codes-download=Download
|
||||
recovery-codes-copy=Copy
|
||||
recovery-codes-copied=Copied
|
||||
recovery-codes-confirmation-message=I have saved these codes somewhere safe
|
||||
recovery-codes-action-complete=Complete setup
|
||||
recovery-codes-action-cancel=Cancel setup
|
||||
recovery-codes-download-file-header=Keep these recovery codes somewhere safe.
|
||||
recovery-codes-download-file-description=Recovery codes are single-use passcodes that allow you to sign in to your account if you do not have access to your authenticator.
|
||||
recovery-codes-download-file-date= These codes were generated on
|
||||
recovery-codes-label-default=Recovery codes
|
||||
|
||||
# WebAuthn
|
||||
webauthn-display-name=Security Key
|
||||
webauthn-help-text=Use your security key to sign in.
|
||||
webauthn-passwordless-display-name=Security Key
|
||||
webauthn-passwordless-help-text=Use your security key for passwordless sign in.
|
||||
webauthn-login-title=Security Key login
|
||||
webauthn-registration-title=Security Key Registration
|
||||
webauthn-available-authenticators=Available Security Keys
|
||||
webauthn-unsupported-browser-text=WebAuthn is not supported by this browser. Try another one or contact your administrator.
|
||||
webauthn-doAuthenticate=Sign in with Security Key
|
||||
webauthn-createdAt-label=Created
|
||||
|
||||
# WebAuthn Error
|
||||
webauthn-error-title=Security Key Error
|
||||
webauthn-error-registration=Failed to register your Security key.<br/> {0}
|
||||
webauthn-error-api-get=Failed to authenticate by the Security key.<br/> {0}
|
||||
webauthn-error-different-user=First authenticated user is not the one authenticated by the Security key.
|
||||
webauthn-error-auth-verification=Security key authentication result is invalid.<br/> {0}
|
||||
webauthn-error-register-verification=Security key registration result is invalid.<br/> {0}
|
||||
webauthn-error-user-not-found=Unknown user authenticated by the Security key.
|
||||
|
||||
# Identity provider
|
||||
identity-provider-redirector=Connect with another Identity Provider
|
||||
identity-provider-login-label=Or sign in with
|
||||
idp-email-verification-display-name=Email Verification
|
||||
idp-email-verification-help-text=Link your account by validating your email.
|
||||
idp-username-password-form-display-name=Username and password
|
||||
idp-username-password-form-help-text=Link your account by logging in.
|
||||
|
||||
finalDeletionConfirmation=If you delete your account, it cannot be restored. To keep your account, click Cancel.
|
||||
irreversibleAction=This action is irreversible
|
||||
deleteAccountConfirm=Delete account confirmation
|
||||
|
||||
deletingImplies=Deleting your account implies:
|
||||
errasingData=Erasing all your data
|
||||
loggingOutImmediately=Logging you out immediately
|
||||
accountUnusable=Any subsequent use of the application will not be possible with this account
|
||||
userDeletedSuccessfully=User deleted successfully
|
||||
|
||||
access-denied=Access denied
|
||||
access-denied-when-idp-auth=Access denied when authenticating with {0}
|
||||
|
||||
frontchannel-logout.title=Logging out
|
||||
frontchannel-logout.message=You are logging out from following apps
|
||||
logoutConfirmTitle=Logging out
|
||||
logoutConfirmHeader=Do you want to log out?
|
||||
doLogout=Logout
|
||||
|
||||
readOnlyUsernameMessage=You can''t update your username as it is read-only.
|
||||
609
keycloak_themes/edm2/login/resources/css/login.css
Normal file
|
|
@ -0,0 +1,609 @@
|
|||
/* Patternfly CSS places a "bg-login.jpg" as the background on this ".login-pf" class.
|
||||
This clashes with the "keycloak-bg.png' background defined on the body below.
|
||||
Therefore the Patternfly background must be set to none. */
|
||||
.login-pf {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.login-pf body {
|
||||
background: url("../img/keycloak-bg.png") no-repeat center center fixed;
|
||||
background-size: cover;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
textarea.pf-c-form-control {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.pf-c-alert__title {
|
||||
font-size: var(--pf-global--FontSize--xs);
|
||||
}
|
||||
|
||||
p.instruction {
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.pf-c-button.pf-m-control {
|
||||
|
||||
}
|
||||
|
||||
h1#kc-page-title {
|
||||
margin-top: 10px;
|
||||
color: rgb(163, 163, 163);
|
||||
}
|
||||
|
||||
#kc-locale ul {
|
||||
background-color: var(--pf-global--BackgroundColor--100);
|
||||
display: none;
|
||||
top: 20px;
|
||||
min-width: 100px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#kc-locale-dropdown{
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#kc-locale-dropdown:hover ul {
|
||||
display:block;
|
||||
}
|
||||
|
||||
#kc-locale-dropdown a {
|
||||
color: var(--pf-global--Color--200);
|
||||
text-align: right;
|
||||
font-size: var(--pf-global--FontSize--sm);
|
||||
}
|
||||
|
||||
a#kc-current-locale-link::after {
|
||||
content: "\2c5";
|
||||
margin-left: var(--pf-global--spacer--xs)
|
||||
}
|
||||
|
||||
.login-pf .container {
|
||||
padding-top: 40px;
|
||||
}
|
||||
|
||||
.login-pf a:hover {
|
||||
color: #0099d3;
|
||||
}
|
||||
|
||||
#kc-logo {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div.kc-logo-text {
|
||||
background-image: url(../img/keycloak-logo-text.png);
|
||||
background-repeat: no-repeat;
|
||||
height: 63px;
|
||||
width: 300px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
div.kc-logo-text span {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#kc-header {
|
||||
color: #ededed;
|
||||
overflow: visible;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#kc-header-wrapper {
|
||||
font-size: 29px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 3px;
|
||||
line-height: 1.2em;
|
||||
padding: 20px 0px 0px 0px;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
#kc-content {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#kc-attempted-username {
|
||||
font-size: 20px;
|
||||
font-family: inherit;
|
||||
font-weight: normal;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
#kc-username {
|
||||
text-align: center;
|
||||
margin-bottom:-10px;
|
||||
}
|
||||
|
||||
#kc-webauthn-settings-form {
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
#kc-form-webauthn .select-auth-box-parent {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#kc-form-webauthn .select-auth-box-desc {
|
||||
color: var(--pf-global--palette--black-600);
|
||||
}
|
||||
|
||||
#kc-form-webauthn .select-auth-box-headline {
|
||||
color: var(--pf-global--Color--300);
|
||||
}
|
||||
|
||||
#kc-form-webauthn .select-auth-box-icon {
|
||||
flex: 0 0 3em;
|
||||
}
|
||||
|
||||
#kc-form-webauthn .select-auth-box-icon-properties {
|
||||
margin-top: 10px;
|
||||
font-size: 1.8em;
|
||||
}
|
||||
|
||||
#kc-form-webauthn .select-auth-box-icon-properties.unknown-transport-class {
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
#kc-form-webauthn .pf-l-stack__item {
|
||||
margin: -1px 0;
|
||||
}
|
||||
|
||||
#kc-content-wrapper {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
#kc-form-wrapper {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#kc-info {
|
||||
margin: 20px -40px -30px;
|
||||
}
|
||||
|
||||
#kc-info-wrapper {
|
||||
font-size: 13px;
|
||||
padding: 15px 35px;
|
||||
background-color: #F0F0F0;
|
||||
}
|
||||
|
||||
#kc-form-options span {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#kc-form-options .checkbox {
|
||||
margin-top: 0;
|
||||
color: #72767b;
|
||||
}
|
||||
|
||||
#kc-terms-text {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#kc-registration-terms-text {
|
||||
max-height: 100px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
#kc-registration {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* TOTP */
|
||||
|
||||
.subtitle {
|
||||
text-align: right;
|
||||
margin-top: 30px;
|
||||
color: #909090;
|
||||
}
|
||||
|
||||
.required {
|
||||
color: var(--pf-global--danger-color--200);
|
||||
}
|
||||
|
||||
ol#kc-totp-settings {
|
||||
margin: 0;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
ul#kc-totp-supported-apps {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#kc-totp-secret-qr-code {
|
||||
max-width:150px;
|
||||
max-height:150px;
|
||||
}
|
||||
|
||||
#kc-totp-secret-key {
|
||||
background-color: #fff;
|
||||
color: #333333;
|
||||
font-size: 16px;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
/* OAuth */
|
||||
|
||||
#kc-oauth h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#kc-oauth ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#kc-oauth ul li {
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||
font-size: 12px;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
#kc-oauth ul li:first-of-type {
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
#kc-oauth .kc-role {
|
||||
display: inline-block;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
/* Code */
|
||||
#kc-code textarea {
|
||||
width: 100%;
|
||||
height: 8em;
|
||||
}
|
||||
|
||||
/* Social */
|
||||
.kc-social-links {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.kc-social-links li {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.kc-social-provider-logo {
|
||||
font-size: 23px;
|
||||
width: 30px;
|
||||
height: 25px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.kc-social-gray {
|
||||
color: var(--pf-global--Color--200);
|
||||
}
|
||||
|
||||
.kc-social-item {
|
||||
margin-bottom: var(--pf-global--spacer--sm);
|
||||
font-size: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.kc-social-provider-name {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.kc-social-icon-text {
|
||||
left: -15px;
|
||||
}
|
||||
|
||||
.kc-social-grid {
|
||||
display:grid;
|
||||
grid-column-gap: 10px;
|
||||
grid-row-gap: 5px;
|
||||
grid-column-end: span 6;
|
||||
--pf-l-grid__item--GridColumnEnd: span 6;
|
||||
}
|
||||
|
||||
.kc-social-grid .kc-social-icon-text {
|
||||
left: -10px;
|
||||
}
|
||||
|
||||
.kc-login-tooltip {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.kc-social-section {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.kc-social-section hr{
|
||||
margin-bottom: 10px
|
||||
}
|
||||
|
||||
.kc-login-tooltip .kc-tooltip-text{
|
||||
top:-3px;
|
||||
left:160%;
|
||||
background-color: black;
|
||||
visibility: hidden;
|
||||
color: #fff;
|
||||
|
||||
min-width:130px;
|
||||
text-align: center;
|
||||
border-radius: 2px;
|
||||
box-shadow:0 1px 8px rgba(0,0,0,0.6);
|
||||
padding: 5px;
|
||||
|
||||
position: absolute;
|
||||
opacity:0;
|
||||
transition:opacity 0.5s;
|
||||
}
|
||||
|
||||
/* Show tooltip */
|
||||
.kc-login-tooltip:hover .kc-tooltip-text {
|
||||
visibility: visible;
|
||||
opacity:0.7;
|
||||
}
|
||||
|
||||
/* Arrow for tooltip */
|
||||
.kc-login-tooltip .kc-tooltip-text::after {
|
||||
content: " ";
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 100%;
|
||||
margin-top: -5px;
|
||||
border-width: 5px;
|
||||
border-style: solid;
|
||||
border-color: transparent black transparent transparent;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#kc-container-wrapper {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.login-pf .container {
|
||||
padding-right: 80px;
|
||||
}
|
||||
|
||||
#kc-locale {
|
||||
position: relative;
|
||||
text-align: right;
|
||||
z-index: 9999;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
|
||||
.login-pf body {
|
||||
background: white;
|
||||
}
|
||||
|
||||
#kc-header {
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
float: none;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#kc-header-wrapper {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
padding: 20px 0 0 0;
|
||||
color: #72767b;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
div.kc-logo-text {
|
||||
margin: 0;
|
||||
width: 150px;
|
||||
height: 32px;
|
||||
background-size: 100%;
|
||||
}
|
||||
|
||||
#kc-form {
|
||||
float: none;
|
||||
}
|
||||
|
||||
#kc-info-wrapper {
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.login-pf .container {
|
||||
padding-top: 15px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
#kc-locale {
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
text-align: right;
|
||||
z-index: 9999;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-height: 646px) {
|
||||
#kc-container-wrapper {
|
||||
bottom: 12%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-height: 645px) {
|
||||
#kc-container-wrapper {
|
||||
padding-top: 50px;
|
||||
top: 20%;
|
||||
}
|
||||
}
|
||||
|
||||
.card-pf form.form-actions .btn {
|
||||
float: right;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
#kc-form-buttons {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.login-pf-page .login-pf-brand {
|
||||
margin-top: 20px;
|
||||
max-width: 360px;
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
.select-auth-box-arrow{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 2rem;
|
||||
}
|
||||
|
||||
.select-auth-box-icon{
|
||||
display: flex;
|
||||
flex: 0 0 2em;
|
||||
justify-content: center;
|
||||
margin-right: 1rem;
|
||||
margin-left: 3rem;
|
||||
}
|
||||
|
||||
.select-auth-box-parent{
|
||||
border-top: 1px solid var(--pf-global--palette--black-200);
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.select-auth-box-parent:hover{
|
||||
background-color: #f7f8f8;
|
||||
}
|
||||
|
||||
.select-auth-container {
|
||||
padding-bottom: 0px !important;
|
||||
}
|
||||
|
||||
.select-auth-box-headline {
|
||||
font-size: var(--pf-global--FontSize--md);
|
||||
color: var(--pf-global--primary-color--100);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.select-auth-box-desc {
|
||||
font-size: var(--pf-global--FontSize--sm);
|
||||
}
|
||||
|
||||
.select-auth-box-paragraph {
|
||||
text-align: center;
|
||||
font-size: var(--pf-global--FontSize--md);
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.card-pf {
|
||||
margin: 0 auto;
|
||||
box-shadow: var(--pf-global--BoxShadow--lg);
|
||||
padding: 0 20px;
|
||||
max-width: 500px;
|
||||
border-radius: 15px;
|
||||
|
||||
}
|
||||
|
||||
/*phone*/
|
||||
@media (max-width: 100px) {
|
||||
.login-pf-page .card-pf {
|
||||
max-width: 500px;
|
||||
padding: 0 20px;
|
||||
border-top: 4px solid;
|
||||
box-shadow: var(--pf-global--BoxShadow--lg);
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
border-radius: 25px;
|
||||
border-color: var(--pf-global--primary-color--100);
|
||||
}
|
||||
|
||||
.kc-social-grid {
|
||||
grid-column-end: 12;
|
||||
--pf-l-grid__item--GridColumnEnd: span 12;
|
||||
}
|
||||
|
||||
.kc-social-grid .kc-social-icon-text {
|
||||
left: -15px;
|
||||
}
|
||||
}
|
||||
|
||||
.login-pf-page .login-pf-signup {
|
||||
font-size: 15px;
|
||||
color: #72767b;
|
||||
}
|
||||
#kc-content-wrapper .row {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.login-pf-page.login-pf-page-accounts {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.login-pf-page .btn-primary {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.login-pf-page .list-view-pf .list-group-item {
|
||||
border-bottom: 1px solid #ededed;
|
||||
}
|
||||
|
||||
.login-pf-page .list-view-pf-description {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#kc-form-login div.form-group:last-of-type,
|
||||
#kc-register-form div.form-group:last-of-type,
|
||||
#kc-update-profile-form div.form-group:last-of-type,
|
||||
#kc-update-email-form div.form-group:last-of-type{
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.no-bottom-margin {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#kc-back {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
/* Recovery codes */
|
||||
.kc-recovery-codes-warning {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
.kc-recovery-codes-warning .pf-c-alert__description p {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
.kc-recovery-codes-list {
|
||||
list-style: none;
|
||||
columns: 2;
|
||||
margin: 16px 0;
|
||||
padding: 16px 16px 8px 16px;
|
||||
border: 1px solid #D2D2D2;
|
||||
}
|
||||
.kc-recovery-codes-list li {
|
||||
margin-bottom: 8px;
|
||||
font-size: 11px;
|
||||
}
|
||||
.kc-recovery-codes-list li span {
|
||||
color: #6A6E73;
|
||||
width: 16px;
|
||||
text-align: right;
|
||||
display: inline-block;
|
||||
margin-right: 1px;
|
||||
}
|
||||
|
||||
.kc-recovery-codes-actions {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
.kc-recovery-codes-actions button {
|
||||
padding-left: 0;
|
||||
}
|
||||
.kc-recovery-codes-actions button i {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.kc-recovery-codes-confirmation {
|
||||
align-items: baseline;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
/* End Recovery codes */
|
||||
44
keycloak_themes/edm2/login/resources/css/styles.css
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
.login-pf body {
|
||||
background: #39a5dc;
|
||||
background-size: cover;
|
||||
height: 100%;
|
||||
}
|
||||
.login-pf body {
|
||||
background: url("../img/xxx.png") no-repeat center center fixed;
|
||||
background-size: cover;
|
||||
background-color: rgba(245, 245, 245, 0.896);
|
||||
height: 100%;
|
||||
}
|
||||
div.kc-logo-text {
|
||||
background-image: url("../img/logo-bangkok4.png");
|
||||
background-repeat: no-repeat;
|
||||
height: 192px;
|
||||
max-width: 192px;
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.pf-c-button.pf-m-primary {
|
||||
border-radius: 5px;
|
||||
border-color: 2px black;
|
||||
background-color: rgb(147, 146, 146);
|
||||
}
|
||||
|
||||
.pf-c-form-control {
|
||||
background-color: whitesmoke;
|
||||
border-color: rgb(188, 176, 176);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.pf-c-form__label-text {
|
||||
color: rgb(122, 122, 122);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
h1#kc-page-title {
|
||||
margin-top: 10px;
|
||||
color: rgb(163, 163, 163);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
BIN
keycloak_themes/edm2/login/resources/img/edm-logo-text.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
keycloak_themes/edm2/login/resources/img/edm-logo-textasdasd.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 513 B |
BIN
keycloak_themes/edm2/login/resources/img/feedback-error-sign.png
Normal file
|
After Width: | Height: | Size: 343 B |
|
After Width: | Height: | Size: 678 B |
|
After Width: | Height: | Size: 410 B |
|
After Width: | Height: | Size: 513 B |
|
After Width: | Height: | Size: 646 B |
BIN
keycloak_themes/edm2/login/resources/img/grey1.png
Normal file
|
After Width: | Height: | Size: 257 KiB |
BIN
keycloak_themes/edm2/login/resources/img/grey2.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
keycloak_themes/edm2/login/resources/img/keycloak-bg.png
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
keycloak_themes/edm2/login/resources/img/keycloak-logo-text.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
keycloak_themes/edm2/login/resources/img/keycloak-logo.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
keycloak_themes/edm2/login/resources/img/logo-bangkok.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
keycloak_themes/edm2/login/resources/img/logo-bangkok2.png
Normal file
|
After Width: | Height: | Size: 219 KiB |
BIN
keycloak_themes/edm2/login/resources/img/logo-bangkok3.png
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
keycloak_themes/edm2/login/resources/img/logo-bangkok4.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
keycloak_themes/edm2/login/resources/img/logo.png
Normal file
|
After Width: | Height: | Size: 4.2 MiB |
3
keycloak_themes/edm2/login/theme.properties
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
parent=keycloak
|
||||
import=common/keycloak
|
||||
styles=css/login.css css/styles.css
|
||||