EntityDetailsView.vue 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. <template>
  2. <Section title="Entity Details">
  3. <template #toolbar>
  4. <button @click="goBack" class="back-button">
  5. <HugeiconsIcon :icon="ArrowLeftIcon" width="1.2em" height="1.2em" />
  6. <span>Back</span>
  7. </button>
  8. </template>
  9. <div v-if="!entityDetails">
  10. <p>Loading entity details...</p>
  11. </div>
  12. <template v-else>
  13. <dl>
  14. <dt>Type</dt>
  15. <dd>
  16. <router-link :to="{ name: 'Entities' }" class="entity-type-link">
  17. {{ entityType }}
  18. </router-link>
  19. </dd>
  20. <dt v-if="entityDetails.title">Title</dt>
  21. <dd v-if="entityDetails.title">{{ entityDetails.title }}</dd>
  22. <template v-if="entityDetails.fields">
  23. <template v-for="(value, key) in entityDetails.fields" :key="key">
  24. <dt>{{ key }}</dt>
  25. <dd>{{ value }}</dd>
  26. </template>
  27. </template>
  28. </dl>
  29. <p v-if="!entityDetails.title && (!entityDetails.fields || Object.keys(entityDetails.fields).length === 0)">No details available for this entity.</p>
  30. <hr />
  31. <h3>Dashboard Entity Directories</h3>
  32. <div v-if="filteredDirectories.length > 0" class="directories-section">
  33. <ul class="directory-list">
  34. <li v-for="(directory, idx) in filteredDirectories" :key="idx">
  35. <router-link
  36. :to="{
  37. name: 'Dashboard',
  38. params: {
  39. title: directory,
  40. entityType: entityType,
  41. entityKey: entityKey
  42. }
  43. }">
  44. {{ directory }}
  45. </router-link>
  46. </li>
  47. </ul>
  48. </div>
  49. <p v-else>No directories found for this entity.
  50. <a href = "https://docs.olivetin.app/dashboards/entity-directories.html" target = "_blank">Learn more</a>
  51. </p>
  52. </template>
  53. </Section>
  54. </template>
  55. <script setup>
  56. import { ref, computed, onMounted } from 'vue'
  57. import { useRouter } from 'vue-router'
  58. import { HugeiconsIcon } from '@hugeicons/vue'
  59. import { ArrowLeftIcon } from '@hugeicons/core-free-icons'
  60. import Section from 'picocrank/vue/components/Section.vue'
  61. const router = useRouter()
  62. const entityDetails = ref(null)
  63. const props = defineProps({
  64. entityType: String,
  65. entityKey: String
  66. })
  67. const filteredDirectories = computed(() => {
  68. if (!entityDetails.value?.directories) {
  69. return []
  70. }
  71. return entityDetails.value.directories.filter(d => d)
  72. })
  73. function goBack() {
  74. router.push({ name: 'Entities' })
  75. }
  76. async function fetchEntityDetails() {
  77. try {
  78. const response = await window.client.getEntity({
  79. type: props.entityType,
  80. uniqueKey: props.entityKey
  81. })
  82. entityDetails.value = response
  83. } catch (err) {
  84. console.error('Failed to fetch entity details:', err)
  85. window.showBigError('fetch-entity-details', 'getting entity details', err, false)
  86. }
  87. }
  88. onMounted(() => {
  89. fetchEntityDetails()
  90. })
  91. </script>
  92. <style scoped>
  93. .back-button {
  94. display: flex;
  95. align-items: center;
  96. gap: 0.5em;
  97. padding: 0.5em 1em;
  98. background-color: var(--bg, #fff);
  99. border: 1px solid var(--border-color, #ccc);
  100. border-radius: 0.5em;
  101. cursor: pointer;
  102. font-size: 0.9em;
  103. box-shadow: 0 0 .3em rgba(0, 0, 0, 0.1);
  104. transition: background-color 0.2s, box-shadow 0.2s;
  105. }
  106. .back-button:hover {
  107. background-color: var(--bg-hover, #f5f5f5);
  108. box-shadow: 0 0 .5em rgba(0, 0, 0, 0.15);
  109. }
  110. .directories-section h3 {
  111. margin-bottom: 0.5em;
  112. font-size: 1.1em;
  113. }
  114. .directory-list a {
  115. text-decoration: none;
  116. padding: 0.5em;
  117. display: inline-block;
  118. border-radius: 0.3em;
  119. transition: background-color 0.2s;
  120. }
  121. .directory-list a:hover {
  122. background-color: var(--bg-hover, #f5f5f5);
  123. text-decoration: underline;
  124. }
  125. .entity-type-link {
  126. text-decoration: none;
  127. transition: opacity 0.2s;
  128. }
  129. .entity-type-link:hover {
  130. text-decoration: underline;
  131. opacity: 0.8;
  132. }
  133. hr {
  134. border: 0;
  135. border-top: 1px solid var(--border-color, #ccc);
  136. }
  137. @media (prefers-color-scheme: dark) {
  138. .back-button {
  139. background-color: var(--bg, #111);
  140. border-color: var(--border-color, #333);
  141. }
  142. .back-button:hover {
  143. background-color: var(--bg-hover, #222);
  144. }
  145. .directories-section {
  146. border-top-color: var(--border-color, #333);
  147. }
  148. .directory-list a:hover {
  149. background-color: var(--bg-hover, #222);
  150. }
  151. }
  152. </style>