Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion structures-frontend-next/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,11 @@ declare module 'vue' {
SidebarItem: typeof import('./src/components/SidebarItem.vue')['default']
SideNav: typeof import('./src/components/SideNav.vue')['default']
Structure: typeof import('./src/components/structures/flow-components/Structure.vue')['default']
StructureDataViewModal: typeof import('./src/components/modals/StructureDataViewModal.vue')['default']
StructureItemModal: typeof import('./src/components/modals/StructureItemModal.vue')['default']
StructureNode: typeof import('./src/components/structures/flow-components/StructureNode.vue')['default']
StructureSettings: typeof import('./src/components/structures/sidebar-dashboard/StructureSettings.vue')['default']
StructureSidebarDashboard: typeof import('./src/components/structures/StructureSidebarDashboard.vue')['default']
StructureSidebarDashboard: typeof import('./src/components/structures/sidebar-dashboard/StructureSidebarDashboard.vue')['default']
StructuresList: typeof import('./src/components/StructuresList.vue')['default']
Tab: typeof import('primevue/tab')['default']
TabList: typeof import('primevue/tablist')['default']
Expand Down
115 changes: 112 additions & 3 deletions structures-frontend-next/src/components/ProjectStructuresTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
import { Component, Vue, Prop, Watch, Ref } from 'vue-facing-decorator'
import CrudTable from '@/components/CrudTable.vue'
import StructureItemModal from '@/components/modals/StructureItemModal.vue'
import StructureDataViewModal from '@/components/modals/StructureDataViewModal.vue'
import { Structure, Structures } from '@kinotic/structures-api'
import type { CrudHeader } from '@/types/CrudHeader'
import { APPLICATION_STATE } from '@/states/IApplicationState'
import type { Identifiable, IterablePage, Pageable } from '@kinotic/continuum-client'
import DatetimeUtil from "@/util/DatetimeUtil"

@Component({
components: { CrudTable, StructureItemModal }
components: { CrudTable, StructureItemModal, StructureDataViewModal }
})
export default class ProjectStructuresTable extends Vue {
@Prop({ required: true }) applicationId!: string
Expand All @@ -24,14 +25,18 @@ export default class ProjectStructuresTable extends Vue {
{ field: 'description', header: 'Description', sortable: false },
{ field: 'created', header: 'Created', sortable: false },
{ field: 'updated', header: 'Updated', sortable: false },
{ field: 'published', header: 'Status', sortable: false }
{ field: 'published', header: 'Status', sortable: false, centered: true }
]

searchText: string = ''
showModal = false
showItemModal = false
selectedStructure: Structure | null = null
isInitialized = false
public DatetimeUtil = DatetimeUtil
actionMenus: any[] = []
currentActionItem: Structure | null = null
private dataSource1 = Structures.getStructureService()

mounted() {
this.searchText = (this.$route.query['search-structure'] as string) || ''
Expand Down Expand Up @@ -100,6 +105,16 @@ export default class ProjectStructuresTable extends Vue {
this.selectedStructure = null
}

openItemModal(item: Structure) {
this.selectedStructure = item
this.showItemModal = true
}

closeItemModal() {
this.showItemModal = false
this.selectedStructure = null
}

onAddItem() {
// this.$router.push("/new-structure")
}
Expand All @@ -112,6 +127,63 @@ export default class ProjectStructuresTable extends Vue {
this.openModal(item)
}

toggleMenu(event: Event, item: Structure, index: number) {
this.currentActionItem = item
const menu = this.actionMenus[index]
if (menu) {
menu.toggle(event)
}
}

async publish(item: any) {
item['publishing'] = true
if (confirm('Are you sure you want to Publish this Structure?')) {
let table: any = this.$refs?.crudTable
try {
await this.dataSource1.publish(item.id)
table?.find()
delete item['publishing']
} catch (error: any) {
delete item['publishing']
table?.displayAlert(error.message)
}
}
}

async unPublish(item: any) {
item['publishing'] = true
if (confirm('Are you sure you want to Remove Published Status for this Structure? \nAll data saved under this Structure will be permanently deleted, proceed with caution.')) {
let table: any = this.$refs?.crudTable
try {
await this.dataSource1.unPublish(item.id)
table?.find()
delete item['publishing']
} catch (error: any) {
delete item['publishing']
table?.displayAlert(error.message)
}
}
}

getActionMenu(item: Structure) {
return [
{
label: item.published ? 'Unpublish' : 'Publish',
icon: item.published ? 'pi pi-eye-slash' : 'pi pi-eye',
command: () => (item.published ? this.unPublish(item) : this.publish(item))
},
{
label: 'View',
icon: 'pi pi-file',
command: (e: any) => {
e?.originalEvent?.stopPropagation?.()
e?.originalEvent?.preventDefault?.()
this.openItemModal(item)
}
}
]
}

async markProjectAsActive() {
try {
const header = this.$root?.$refs?.header as { setActiveProjectById?: (appId: string, projId: string) => Promise<void> } | undefined
Expand Down Expand Up @@ -154,14 +226,51 @@ export default class ProjectStructuresTable extends Vue {
{{ DatetimeUtil.formatRelativeDate(item.updated) }}
</span>
</template>
<template #item.published="{ item }">
<div class="w-full text-center">
<Tag
:value="item.published ? 'Published' : 'Unpublished'"
:severity="item.published ? 'success' : 'secondary'"
class="px-2 py-1 text-sm"
rounded
/>
</div>
</template>
<template #item.description="{ item }">
<span>{{ item.description }}</span>
</template>
<template #additional-actions="{ item }">
<div class="flex items-center justify-center">
<Button
icon="pi pi-ellipsis-v"
@click.stop="(event) => toggleMenu(event, item, item.id)"
aria-haspopup="true"
:aria-controls="'action_menu_' + item.id"
type="button"
severity="secondary"
variant="text"
/>
<Menu
:ref="(el) => (actionMenus[item.id] = el)"
:model="getActionMenu(item)"
:popup="true"
:id="'action_menu_' + item.id"
/>
</div>
</template>
</CrudTable>

<StructureItemModal
v-if="showModal && selectedStructure"
v-if="showItemModal && selectedStructure"
:item="selectedStructure"
@close="closeItemModal"
/>

<StructureDataViewModal
v-if="showModal && selectedStructure"
v-model="showModal"
:title="selectedStructure?.name || 'Data View'"
:entity-props="{ structureId: selectedStructure?.id }"
@close="closeModal"
/>
</div>
Expand Down
2 changes: 1 addition & 1 deletion structures-frontend-next/src/components/SideBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export default class Sidebar extends Vue {

<template>
<div class="p-2 fixed rounded-xl top-[64px] left-0 z-40 h-[calc(100vh-64px)]"
:class="[collapsed ? 'w-[64px]' : 'w-[256px]']">
:class="[collapsed ? 'w-[67px]' : 'w-[256px]']">
<div :class="['bg-surface-50 rounded-xl flex flex-col justify-between px-2 py-2 h-full', 'transition-[width] duration-300 ease-in-out w-full']">
<div class="flex flex-col w-full">
<SidebarItem
Expand Down
9 changes: 6 additions & 3 deletions structures-frontend-next/src/components/SidebarItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,16 @@ const iconClass = computed(() => {
<template>
<div
:class="[
'flex items-center py-[9px] cursor-pointer w-full rounded-md hover:bg-surface-200 px-2 pl-1 transition-colors duration-200',
'flex items-center py-[9px] cursor-pointer w-full rounded-md hover:bg-surface-200 px-2 pl-1 transition-colors duration-200',
props.isActive ? '' : 'bg-transparent'
]"
@click="$emit('click')"
>
<div class="min-w-[20px] flex justify-center">
<i :class="['pi', icon, 'text-base', iconClass]" />
<div class="min-w-[20px] flex justify-center items-center">
<i
:class="['pi', icon, props.collapsed ? '' : 'text-base', iconClass]"
:style="props.collapsed ? { fontSize: '14px', lineHeight: '14px' } : {}"
/>
</div>
<div class="w-[8px]"></div>
<div class="overflow-hidden">
Expand Down
33 changes: 28 additions & 5 deletions structures-frontend-next/src/components/StructuresList.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script lang="ts">
import { Component, Vue, Prop, Ref, Watch } from "vue-facing-decorator";
import CrudTable from "@/components/CrudTable.vue";
import StructureDataViewModal from "@/components/modals/StructureDataViewModal.vue";
import StructureItemModal from "@/components/modals/StructureItemModal.vue";
import type {
Identifiable,
Expand All @@ -13,7 +14,7 @@ import type { CrudHeader } from "@/types/CrudHeader";
import DatetimeUtil from "@/util/DatetimeUtil";

@Component({
components: { CrudTable, StructureItemModal },
components: { CrudTable, StructureDataViewModal, StructureItemModal },
})
export default class StructuresList extends Vue {
@Prop({ required: true }) applicationId!: string;
Expand All @@ -33,6 +34,7 @@ export default class StructuresList extends Vue {
];

showModal = false;
showItemModal = false;
selectedStructure: Structure | null = null;
searchText = "";
isInitialized = false;
Expand Down Expand Up @@ -125,6 +127,16 @@ export default class StructuresList extends Vue {
this.selectedStructure = null;
}

openItemModal(item: Structure) {
this.selectedStructure = item;
this.showItemModal = true;
}

closeItemModal() {
this.showItemModal = false;
this.selectedStructure = null;
}

handleRowClick(item: Structure): void {
this.openModal(item);
}
Expand Down Expand Up @@ -186,7 +198,11 @@ export default class StructuresList extends Vue {
{
label: "View",
icon: "pi pi-file",
command: () => this.handleRowClick(item),
command: (e: any) => {
e?.originalEvent?.stopPropagation?.();
e?.originalEvent?.preventDefault?.();
this.openItemModal(item);
}
},
];
}
Expand Down Expand Up @@ -227,7 +243,6 @@ export default class StructuresList extends Vue {
/>
</div>
</template>

<template #additional-actions="{ item }">
<div class="flex items-center justify-center">
<Button
Expand All @@ -249,10 +264,18 @@ export default class StructuresList extends Vue {
</template>
</CrudTable>

<StructureDataViewModal
v-if="selectedStructure"
v-model="showModal"
:title="selectedStructure?.name || 'Data View'"
:entity-props="{ structureId: selectedStructure?.id }"
@close="closeModal"
/>

<StructureItemModal
v-if="showModal && selectedStructure"
v-if="showItemModal && selectedStructure"
:item="selectedStructure"
@close="closeModal"
@close="closeItemModal"
/>
</div>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<script lang="ts">
import EntityList from "@/pages/EntityList.vue";
import { Component, Vue, Prop, Emit } from "vue-facing-decorator";

@Component({
components: { EntityList }
})
export default class StructureDataViewModal extends Vue {
@Prop({ default: false }) readonly modelValue!: boolean;
@Prop({ default: "Data View" }) readonly title!: string;
@Prop({ default: () => ({}) }) readonly entityProps!: Record<string, unknown>;

get visible(): boolean {
return this.modelValue;
}

set visible(val: boolean) {
this.updateModelValue(val);
}

@Emit("update:modelValue")
updateModelValue(val: boolean) {
return val;
}

@Emit("open")
emitOpen() {
return true;
}

@Emit("close")
emitClose() {
return true;
}

mounted() {
if (this.visible) this.emitOpen();
window.addEventListener("keydown", this.onKeydown);
}

beforeUnmount() {
window.removeEventListener("keydown", this.onKeydown);
}

onKeydown = (e: KeyboardEvent) => {
if (e.key === "Escape" && this.visible) {
this.onHide();
}
};

onHide() {
this.visible = false;
this.emitClose();
}
}
</script>
<template>
<div v-show="visible" class="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50">
<div class="relative w-full h-screen bg-white shadow-lg overflow-hidden overflow-y-scroll">
<div class="flex items-center justify-between p-4 border-b border-gray-200">
<h3 class="text-xl font-semibold text-gray-900">{{ title }}</h3>
<button @click="onHide" class="text-gray-400 hover:text-gray-900 hover:bg-gray-200 rounded-lg text-sm w-8 h-8 flex items-center justify-center">
<svg class="w-3 h-3" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6" />
</svg>
</button>
</div>
<div class="h-full">
<EntityList v-bind="entityProps" />
</div>
</div>
</div>
</template>
Loading