Adding TenantPropertyService screen
This commit is contained in:
parent
8c7658e090
commit
aa738e1e66
@ -1,2 +1,2 @@
|
||||
VITE_API_BASE_URL=http://localhost:3000
|
||||
VITE_API_BASE_URL=http://localhost:3000/api
|
||||
VITE_ROUTER_BASE=/
|
||||
|
||||
901
package-lock.json
generated
901
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -27,11 +27,14 @@
|
||||
"devDependencies": {
|
||||
"@types/d3-sankey": "^0.12.1",
|
||||
"@vitejs/plugin-vue": "^3.1.0",
|
||||
"autoprefixer": "^10.4.16",
|
||||
"eslint": "^8.51.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-plugin-vue": "^9.15.1",
|
||||
"postcss": "^8.4.31",
|
||||
"prettier": "^2.8.8",
|
||||
"sass": "^1.63.6",
|
||||
"tailwindcss": "^3.3.5",
|
||||
"vite": "^3.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
6
postcss.config.js
Normal file
6
postcss.config.js
Normal file
@ -0,0 +1,6 @@
|
||||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
68
src/components/BaseModal.vue
Normal file
68
src/components/BaseModal.vue
Normal file
@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<Transition>
|
||||
<div
|
||||
v-if="modalActive"
|
||||
id="createProductModal"
|
||||
tabindex="-1"
|
||||
aria-hidden="true"
|
||||
class="overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-fulloverflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full flex"
|
||||
>
|
||||
<div class="relative p-4 w-full max-w-2xl max-h-full">
|
||||
<!-- Modal content -->
|
||||
<div
|
||||
class="relative p-4 bg-white rounded-lg shadow dark:bg-gray-800 sm:p-5"
|
||||
>
|
||||
<!-- Modal header -->
|
||||
<div
|
||||
class="flex justify-between items-center pb-4 mb-4 rounded-t border-b sm:mb-5 dark:border-gray-600"
|
||||
>
|
||||
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">
|
||||
Add Property
|
||||
</h3>
|
||||
<button
|
||||
type="button"
|
||||
class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center dark:hover:bg-gray-600 dark:hover:text-white"
|
||||
data-modal-target="createProductModal"
|
||||
data-modal-toggle="createProductModal"
|
||||
@click="$emit('close-modal')"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="w-5 h-5"
|
||||
fill="currentColor"
|
||||
viewbox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
<span class="sr-only">Close modal</span>
|
||||
</button>
|
||||
</div>
|
||||
<!-- Modal body -->
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
<div
|
||||
v-if="modalActive"
|
||||
modal-backdrop=""
|
||||
class="bg-gray-900 bg-opacity-50 dark:bg-opacity-80 fixed inset-0 z-40"
|
||||
></div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
defineEmits(["close-modal"]);
|
||||
defineProps({
|
||||
modalActive: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
62
src/components/DataTable.vue
Normal file
62
src/components/DataTable.vue
Normal file
@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<table class="w-full text-left text-sm text-gray-500 dark:text-gray-400">
|
||||
<thead
|
||||
class="bg-gray-50 text-xs uppercase text-gray-700 dark:bg-gray-700 dark:text-gray-400"
|
||||
>
|
||||
<tr>
|
||||
<th v-for="column in columns" :key="column.key" class="px-4 py-4">
|
||||
{{ column.label }}
|
||||
</th>
|
||||
<th class="px-4 py-4">action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="row in rows"
|
||||
:key="row.name"
|
||||
class="border-b dark:border-gray-700"
|
||||
>
|
||||
<td v-for="column in columns" :key="column.key" class="px-4 py-3">
|
||||
{{ row[column.key] }}
|
||||
</td>
|
||||
<td class="flex items-center px-4 py-3">
|
||||
<button
|
||||
class="flex items-center justify-center rounded-lg bg-blue-700 px-4 py-2 text-sm font-medium text-white hover:bg-blue-800 focus:outline-none focus:ring-4 focus:ring-green-300 dark:bg-green-600 dark:hover:bg-green-700 dark:focus:ring-green-800 mr-2"
|
||||
@click="editProperty(row.name)"
|
||||
>
|
||||
Edit
|
||||
</button>
|
||||
<button
|
||||
class="flex items-center justify-center rounded-lg bg-red-700 px-4 py-2 text-sm font-medium text-white hover:bg-red-800 focus:outline-none focus:ring-4 focus:ring-green-300 dark:bg-green-600 dark:hover:bg-green-700 dark:focus:ring-green-800"
|
||||
@click="deleteProperty(row.name)"
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const emit = defineEmits(["edit", "delete"]);
|
||||
|
||||
defineProps({
|
||||
rows: {
|
||||
type: Array,
|
||||
default: null,
|
||||
},
|
||||
columns: {
|
||||
type: Array,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const editProperty = (name) => {
|
||||
emit("edit", name);
|
||||
};
|
||||
|
||||
const deleteProperty = (name) => {
|
||||
emit("delete", name);
|
||||
};
|
||||
</script>
|
||||
73
src/components/TenantPropertyForm.vue
Normal file
73
src/components/TenantPropertyForm.vue
Normal file
@ -0,0 +1,73 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from "vue";
|
||||
|
||||
import useTenantPropertiesStore from "@/stores/tenantPropertiesStore";
|
||||
|
||||
const emit = defineEmits(["close-modal"]);
|
||||
|
||||
const props = defineProps({
|
||||
username: { type: String, default: "" },
|
||||
sessionIdentifier: { type: String, default: "" },
|
||||
name: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const propertiesStore = useTenantPropertiesStore(props);
|
||||
const property = ref({
|
||||
name: "",
|
||||
value: "",
|
||||
lastEditedBy: "",
|
||||
lastEditedDate: "",
|
||||
});
|
||||
|
||||
const performAction = () => {
|
||||
updateProperty();
|
||||
};
|
||||
|
||||
|
||||
const updateProperty = () => {
|
||||
propertiesStore.updateProperty(property.value);
|
||||
resetProperty();
|
||||
emit("close-modal");
|
||||
};
|
||||
|
||||
const resetProperty = () => {
|
||||
property.value = {};
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
if (props.name) {
|
||||
propertiesStore.getPropertyByName(props.name).then((fetchedProperty) => {
|
||||
property.value = fetchedProperty;
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<form @submit.prevent="performAction">
|
||||
<div class="grid gap-4 mb-4 sm:grid-cols-2">
|
||||
<div>
|
||||
<label for="name" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Name</label>
|
||||
<input v-model="property.name" type="text"
|
||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500"
|
||||
placeholder="Type property name" required="" />
|
||||
</div>
|
||||
<div class="sm:col-span-2">
|
||||
<label for="value" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Value</label>
|
||||
<textarea id="value" v-model="property.value" rows="4"
|
||||
class="block p-2.5 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-primary-500 focus:border-primary-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500"
|
||||
placeholder="Enter value here"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit"
|
||||
class="text-white inline-flex items-center bg-green-700 hover:bg-green-800 focus:ring-4 focus:outline-none focus:ring-green-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-green-600 dark:hover:bg-green-700 dark:focus:ring-green-800">
|
||||
{{ props.name ? "Update" : "Add" }} Property
|
||||
</button>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@ -28,7 +28,7 @@ export function getTenantProperty(key, props) {
|
||||
|
||||
var authKey = getAuthKeyFromProperties(props);
|
||||
console.log(`Fetching TPS Property [${key}]`);
|
||||
fetch(`${apiBaseUrl}/tps?propertyName=${key}&authKey=${authKey}`, {
|
||||
fetch(`${apiBaseUrl}/tps/${key}?authKey=${authKey}`, {
|
||||
credentials: "include", // fetch won't send cookies unless you set credentials
|
||||
})
|
||||
.then((response) => {
|
||||
|
||||
@ -3,28 +3,28 @@ import { routerBase } from "../app.config.js";
|
||||
import HomeView from "../views/HomeView.vue";
|
||||
import AboutView from "../views/AboutView.vue";
|
||||
import DebugFrameView from "../views/DebugFrameView.vue";
|
||||
import SideBarView from "../views/SideBarView.vue";
|
||||
import SearchByReferenceView from "../views/SearchByReferenceView.vue";
|
||||
import InteractionsFlowView from "../views/InteractionsFlowView.vue";
|
||||
import CustomerAccountView from "../views/TelephonyContextView.vue";
|
||||
import TelephonyContextView from "../views/TelephonyContextView.vue";
|
||||
import TenantPropertiesView from "../views/TenantPropertiesView.vue";
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: "/",
|
||||
name: "home",
|
||||
components: { default: HomeView, SideBarView: SideBarView },
|
||||
props: { default: false, SideBarView: true },
|
||||
components: { default: HomeView },
|
||||
props: { default: false },
|
||||
},
|
||||
{
|
||||
path: "/about",
|
||||
name: "about",
|
||||
components: { default: AboutView, SideBarView: SideBarView },
|
||||
components: { default: AboutView },
|
||||
props: { default: false, SideBarView: true },
|
||||
},
|
||||
{
|
||||
path: "/referenceId",
|
||||
name: "referenceId",
|
||||
components: { default: SearchByReferenceView, SideBarView: SideBarView },
|
||||
components: { default: SearchByReferenceView },
|
||||
props: {
|
||||
default: (route) => ({
|
||||
sessionIdentifier: route.query._sessionIdentifier,
|
||||
@ -34,7 +34,7 @@ const routes = [
|
||||
{
|
||||
path: "/interactionsFlow",
|
||||
name: "interactionsFlow",
|
||||
components: { default: InteractionsFlowView, SideBarView: SideBarView },
|
||||
components: { default: InteractionsFlowView },
|
||||
props: {
|
||||
default: (route) => ({
|
||||
sessionIdentifier: route.query._sessionIdentifier,
|
||||
@ -45,7 +45,7 @@ const routes = [
|
||||
{
|
||||
path: "/telephonyContext",
|
||||
name: "telephonyContext",
|
||||
components: { default: CustomerAccountView },
|
||||
components: { default: TelephonyContextView },
|
||||
props: {
|
||||
default: (route) => ({
|
||||
...route.params,
|
||||
@ -61,6 +61,18 @@ const routes = [
|
||||
components: { default: DebugFrameView },
|
||||
props: { default: true },
|
||||
},
|
||||
{
|
||||
path: "/tenantProperties",
|
||||
name: "tenantProperties",
|
||||
components: { default: TenantPropertiesView },
|
||||
props: {
|
||||
default: (route) => ({
|
||||
...route.params,
|
||||
...route.query,
|
||||
sessionIdentifier: route.query._sessionIdentifier,
|
||||
}),
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
console.log(`mounting router on ${routerBase}`);
|
||||
|
||||
120
src/stores/tenantPropertiesStore
Normal file
120
src/stores/tenantPropertiesStore
Normal file
@ -0,0 +1,120 @@
|
||||
import { getAuthKeyFromProperties } from "../helpers/index.js"
|
||||
import { apiBaseUrl } from "../app.config.js";
|
||||
|
||||
export default function useTenantPropertiesStore(props) {
|
||||
const authKey = getAuthKeyFromProperties(props);
|
||||
const store = {
|
||||
authKey: authKey,
|
||||
getColumns: function () {
|
||||
return [
|
||||
{
|
||||
key: 'name',
|
||||
label: 'Name'
|
||||
},
|
||||
{
|
||||
key: 'value',
|
||||
label: 'Value'
|
||||
},
|
||||
{
|
||||
key: 'lastModifiedBy',
|
||||
label: 'Last Modified By'
|
||||
},
|
||||
{
|
||||
key: 'lastModifiedDate',
|
||||
label: 'Last Modified Date'
|
||||
}
|
||||
]
|
||||
},
|
||||
getProperties: function () {
|
||||
return new Promise((resolve, reject) => {
|
||||
fetch(`${apiBaseUrl}/tps?authKey=${authKey}`, {
|
||||
credentials: "include", // fetch won't send cookies unless you set credentials
|
||||
}).then((response) => {
|
||||
// check for error response
|
||||
if (!response.ok) {
|
||||
reject(response.data || response.statusText);
|
||||
}
|
||||
response.json().then((data) => {
|
||||
resolve(data.data);
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
reject(error);
|
||||
});
|
||||
})
|
||||
},
|
||||
getPropertyByName: function (name) {
|
||||
return new Promise((resolve, reject) => {
|
||||
fetch(`${apiBaseUrl}/tps/${name}?authKey=${authKey}`, {
|
||||
credentials: "include", // fetch won't send cookies unless you set credentials
|
||||
}).then((response) => {
|
||||
// check for error response
|
||||
if (!response.ok) {
|
||||
reject(response.data || response.statusText);
|
||||
}
|
||||
response.json().then((data) => {
|
||||
console.log("Found Property:" + JSON.stringify(data));
|
||||
resolve(data.data);
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
reject(error);
|
||||
});
|
||||
})
|
||||
},
|
||||
updateProperty: (property) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const requestOptions = {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ data: property }),
|
||||
};
|
||||
|
||||
fetch(`${apiBaseUrl}/tps?authKey=${authKey}`, requestOptions)
|
||||
.then((response) => {
|
||||
// check for error response
|
||||
if (!response.ok) {
|
||||
reject(response.data || response.statusText);
|
||||
}
|
||||
response.json().then((data) => {
|
||||
console.log("Found Property:" + JSON.stringify(data));
|
||||
resolve(data.data);
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
reject(error);
|
||||
});
|
||||
})
|
||||
},
|
||||
deleteProperty: (name) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const requestOptions = {
|
||||
method: "DELETE"
|
||||
};
|
||||
|
||||
fetch(`${apiBaseUrl}/tps/${name}?authKey=${authKey}`, requestOptions)
|
||||
.then((response) => {
|
||||
// check for error response
|
||||
if (!response.ok) {
|
||||
reject(response.data || response.statusText);
|
||||
}
|
||||
response.json().then((data) => {
|
||||
console.log("Found Property:" + JSON.stringify(data));
|
||||
resolve(data.data);
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
reject(error);
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return store;
|
||||
}
|
||||
|
||||
@ -1,3 +1,7 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
h1 {
|
||||
font-size: 18px;
|
||||
line-height: 19px;
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
<script setup>
|
||||
const transferSummaryHTML = `Janice Jones from Acme.com authenticated using onetime passcode authentication. They successfully changed the quantity on latest order from 10 to 12. She wants to dicuss with someone to alter payment arrangements payment due date. Transferring to queue.`;
|
||||
|
||||
const scriptElementName = "script";
|
||||
const integrationCardDoc = `<html>
|
||||
|
||||
@ -83,7 +82,9 @@ const integrationCardDoc = `<html>
|
||||
</script>
|
||||
<template>
|
||||
<div class="home">
|
||||
<h1>Engagement Orchestration - Microservice Examples</h1>
|
||||
<h1 class="text-3xl font-bold underline">
|
||||
Engagement Orchestration - Microservice Examples
|
||||
</h1>
|
||||
<h2>Introduction</h2>
|
||||
<p>
|
||||
This site provides a set of microservices to augment Engagement
|
||||
@ -111,11 +112,15 @@ const integrationCardDoc = `<html>
|
||||
transferSummary: transferSummaryHTML,
|
||||
integrationCardDoc: integrationCardDoc,
|
||||
integrationCardTitle: 'Integration Card',
|
||||
crsScore: 72,
|
||||
},
|
||||
}"
|
||||
>Telephony Context</router-link
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<router-link to="/tenantProperties">Tenant Properties</router-link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -1,99 +0,0 @@
|
||||
<script>
|
||||
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
||||
import { SidebarMenu } from "vue-sidebar-menu";
|
||||
import "vue-sidebar-menu/dist/vue-sidebar-menu.css";
|
||||
import { h, markRaw } from "vue";
|
||||
|
||||
const separator = {
|
||||
template: '<hr style="border-color: rgba(0, 0, 0, 0.1); margin: 20px;">',
|
||||
};
|
||||
|
||||
const faIcon = (props) => {
|
||||
return {
|
||||
element: markRaw({
|
||||
render: () => h("div", [h(FontAwesomeIcon, { size: "lg", ...props })]),
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
export default {
|
||||
name: "SideBarView",
|
||||
components: {
|
||||
SidebarMenu,
|
||||
},
|
||||
|
||||
// props: {
|
||||
// sidebar: {
|
||||
// type: Boolean,
|
||||
// required: false
|
||||
// }
|
||||
// },
|
||||
data() {
|
||||
return {
|
||||
menu: [
|
||||
{
|
||||
header: "Services",
|
||||
hiddenOnCollapse: true,
|
||||
},
|
||||
{
|
||||
href: "/",
|
||||
title: "Home",
|
||||
icon: faIcon({ icon: "fa-solid fa-house" }),
|
||||
},
|
||||
{
|
||||
href: "/about",
|
||||
title: "About",
|
||||
icon: faIcon({ icon: "fa-solid fa-question" }),
|
||||
},
|
||||
{
|
||||
component: markRaw(separator),
|
||||
},
|
||||
{
|
||||
href: "/referenceId",
|
||||
title: "Contacts Lookup",
|
||||
icon: faIcon({ icon: "fa-solid fa-rectangle-list" }),
|
||||
},
|
||||
{
|
||||
href: "/interactionsFlow",
|
||||
title: "Interactions Flow",
|
||||
icon: faIcon({ icon: "fa-solid fa-route" }),
|
||||
},
|
||||
{
|
||||
href: "/customerAccount/12345",
|
||||
title: "Customer Account Example",
|
||||
icon: faIcon({ icon: "fa-solid fa-id-card" }),
|
||||
},
|
||||
],
|
||||
collapsed: false,
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.onResize();
|
||||
window.addEventListener("resize", this.onResize);
|
||||
console.log();
|
||||
},
|
||||
methods: {
|
||||
onResize() {
|
||||
if (window.innerWidth <= 767) {
|
||||
this.isOnMobile = true;
|
||||
this.collapsed = true;
|
||||
} else {
|
||||
this.isOnMobile = false;
|
||||
this.collapsed = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div v-if="$route.query.sidebar" id="sidebar">
|
||||
<sidebar-menu
|
||||
v-model:collapsed="collapsed"
|
||||
:menu="menu"
|
||||
:show-one-child="true"
|
||||
:relative="true"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<style></style>
|
||||
107
src/views/TenantPropertiesView.vue
Normal file
107
src/views/TenantPropertiesView.vue
Normal file
@ -0,0 +1,107 @@
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, onUpdated } from "vue";
|
||||
import DataTable from "@/components/DataTable.vue";
|
||||
import BaseModel from "@/components/BaseModal.vue";
|
||||
import TenantPropertyForm from "@/components/TenantPropertyForm.vue";
|
||||
|
||||
import useTenantPropertiesStore from "@/stores/tenantPropertiesStore";
|
||||
|
||||
const props = defineProps({
|
||||
username: { type: String, default: "" },
|
||||
sessionIdentifier: { type: String, default: "" }
|
||||
});
|
||||
|
||||
|
||||
const modalActive = ref(null);
|
||||
const name = ref(null);
|
||||
|
||||
const tenantPropertiesStore = useTenantPropertiesStore(props);
|
||||
|
||||
const columns = computed(() => tenantPropertiesStore.getColumns());
|
||||
const rows = ref(null)
|
||||
|
||||
onMounted(() => {
|
||||
tenantPropertiesStore.getProperties().then((properties) => { rows.value = properties });
|
||||
})
|
||||
|
||||
const toggleModal = () => {
|
||||
modalActive.value = !modalActive.value;
|
||||
if (!modalActive.value) {
|
||||
name.value = null;
|
||||
}
|
||||
tenantPropertiesStore.getProperties().then((properties) => { rows.value = properties });
|
||||
};
|
||||
|
||||
const openEditModal = (id) => {
|
||||
name.value = id;
|
||||
toggleModal();
|
||||
};
|
||||
|
||||
const deleteProperty = (name) => {
|
||||
tenantPropertiesStore.deleteProperty(name);
|
||||
};
|
||||
|
||||
const refreshData = () => {
|
||||
tenantPropertiesStore.getProperties().then((properties) => { rows.value = properties });
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<!-- Start block -->
|
||||
<section class="bg-gray-50 p-3 antialiased dark:bg-gray-900 sm:p-5">
|
||||
<div class="mx-auto max-w-screen-xl px-4 lg:px-12">
|
||||
<!-- Start coding here -->
|
||||
<div
|
||||
class="relative overflow-hidden bg-white shadow-md dark:bg-gray-800 sm:rounded-lg"
|
||||
>
|
||||
<nav
|
||||
class="flex flex-col items-start justify-between space-y-3 p-4 md:flex-row md:items-center md:space-y-0"
|
||||
aria-label="Table navigation"
|
||||
>
|
||||
<h2
|
||||
class="mb-4 text-3xl font-extrabold leading-none tracking-tight text-gray-900 dark:text-white md:text-4xl"
|
||||
>
|
||||
Tenant Properties
|
||||
</h2>
|
||||
</nav>
|
||||
|
||||
<div
|
||||
class="flex flex-col items-center justify-between space-y-3 p-4 md:flex-row md:space-x-4 md:space-y-0"
|
||||
>
|
||||
<div
|
||||
class="flex w-full flex-shrink-0 flex-col items-stretch justify-end space-y-2 md:w-auto md:flex-row md:items-center md:space-x-3 md:space-y-0"
|
||||
>
|
||||
<button
|
||||
id="createProductModalButton"
|
||||
type="button"
|
||||
data-modal-target="createProductModal"
|
||||
data-modal-toggle="createProductModal"
|
||||
class="flex items-center justify-center rounded-lg bg-green-700 px-4 py-2 text-sm font-medium text-white hover:bg-green-800 focus:outline-none focus:ring-4 focus:ring-green-300 dark:bg-green-600 dark:hover:bg-green-700 dark:focus:ring-green-800"
|
||||
@click="toggleModal"
|
||||
>
|
||||
Add Property
|
||||
</button>
|
||||
<button
|
||||
id="refreshButton"
|
||||
type="button"
|
||||
class="flex items-center justify-center rounded-lg bg-green-700 px-4 py-2 text-sm font-medium text-white hover:bg-green-800 focus:outline-none focus:ring-4 focus:ring-green-300 dark:bg-green-600 dark:hover:bg-green-700 dark:focus:ring-green-800"
|
||||
@click="refreshData"
|
||||
>
|
||||
Refresh Data
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overflow-x-auto">
|
||||
<DataTable
|
||||
:rows="rows"
|
||||
:columns="columns"
|
||||
@edit="openEditModal"
|
||||
@delete="deleteProperty"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<BaseModel :modal-active="modalActive" @close-modal="toggleModal">
|
||||
<TenantPropertyForm v-bind="props" v-model:name="name" @close-modal="toggleModal" />
|
||||
</BaseModel>
|
||||
</section>
|
||||
</template>
|
||||
8
tailwind.config.js
Normal file
8
tailwind.config.js
Normal file
@ -0,0 +1,8 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: ["index.html", "src/**/*.{vue,js,ts,jsx,tsx}"],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
||||
@ -1,4 +1,5 @@
|
||||
import { defineConfig } from "vite";
|
||||
import { fileURLToPath, URL } from "node:url";
|
||||
import vue from "@vitejs/plugin-vue";
|
||||
import { createHtmlPlugin } from "vite-plugin-html";
|
||||
|
||||
@ -36,6 +37,7 @@ export default defineConfig(({ command }) => {
|
||||
resolve: {
|
||||
alias: {
|
||||
vue: "vue/dist/vue.esm-bundler",
|
||||
"@": fileURLToPath(new URL("./src", import.meta.url)),
|
||||
},
|
||||
},
|
||||
};
|
||||
@ -72,6 +74,7 @@ export default defineConfig(({ command }) => {
|
||||
resolve: {
|
||||
alias: {
|
||||
vue: "vue/dist/vue.esm-bundler",
|
||||
"@": fileURLToPath(new URL("./src", import.meta.url)),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user