@karibsen/eponyme 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +609 -0
- package/dist/eponyme.d.mts +15 -0
- package/dist/eponyme.mjs +38 -0
- package/dist/module.d.mts +26 -0
- package/dist/module.json +9 -0
- package/dist/module.mjs +154 -0
- package/dist/runtime/assets/dashboard.css +1 -0
- package/dist/runtime/components/editor/EponymeCollectionPage.d.vue.ts +9 -0
- package/dist/runtime/components/editor/EponymeCollectionPage.vue +238 -0
- package/dist/runtime/components/editor/EponymeCollectionPage.vue.d.ts +9 -0
- package/dist/runtime/components/editor/EponymeCopy.d.vue.ts +7 -0
- package/dist/runtime/components/editor/EponymeCopy.vue +28 -0
- package/dist/runtime/components/editor/EponymeCopy.vue.d.ts +7 -0
- package/dist/runtime/components/editor/EponymeFolderNav.d.vue.ts +7 -0
- package/dist/runtime/components/editor/EponymeFolderNav.vue +146 -0
- package/dist/runtime/components/editor/EponymeFolderNav.vue.d.ts +7 -0
- package/dist/runtime/components/editor/EponymeFolderPage.d.vue.ts +7 -0
- package/dist/runtime/components/editor/EponymeFolderPage.vue +62 -0
- package/dist/runtime/components/editor/EponymeFolderPage.vue.d.ts +7 -0
- package/dist/runtime/components/editor/EponymeForm.d.vue.ts +9 -0
- package/dist/runtime/components/editor/EponymeForm.vue +309 -0
- package/dist/runtime/components/editor/EponymeForm.vue.d.ts +9 -0
- package/dist/runtime/components/editor/EponymeFormPage.d.vue.ts +8 -0
- package/dist/runtime/components/editor/EponymeFormPage.vue +288 -0
- package/dist/runtime/components/editor/EponymeFormPage.vue.d.ts +8 -0
- package/dist/runtime/components/editor/EponymeHistoryDialog.d.vue.ts +14 -0
- package/dist/runtime/components/editor/EponymeHistoryDialog.vue +97 -0
- package/dist/runtime/components/editor/EponymeHistoryDialog.vue.d.ts +14 -0
- package/dist/runtime/components/editor/EponymeNavigationLink.d.vue.ts +14 -0
- package/dist/runtime/components/editor/EponymeNavigationLink.vue +80 -0
- package/dist/runtime/components/editor/EponymeNavigationLink.vue.d.ts +14 -0
- package/dist/runtime/components/editor/EponymePageNavigation.d.vue.ts +8 -0
- package/dist/runtime/components/editor/EponymePageNavigation.vue +58 -0
- package/dist/runtime/components/editor/EponymePageNavigation.vue.d.ts +8 -0
- package/dist/runtime/components/editor/EponymePreviewPanel.d.vue.ts +16 -0
- package/dist/runtime/components/editor/EponymePreviewPanel.vue +100 -0
- package/dist/runtime/components/editor/EponymePreviewPanel.vue.d.ts +16 -0
- package/dist/runtime/components/editor/EponymeSidebar.d.vue.ts +6 -0
- package/dist/runtime/components/editor/EponymeSidebar.vue +244 -0
- package/dist/runtime/components/editor/EponymeSidebar.vue.d.ts +6 -0
- package/dist/runtime/components/editor/EponymeSidebarTree.d.vue.ts +18 -0
- package/dist/runtime/components/editor/EponymeSidebarTree.vue +84 -0
- package/dist/runtime/components/editor/EponymeSidebarTree.vue.d.ts +18 -0
- package/dist/runtime/components/fields/ArrayField.d.vue.ts +19 -0
- package/dist/runtime/components/fields/ArrayField.vue +198 -0
- package/dist/runtime/components/fields/ArrayField.vue.d.ts +19 -0
- package/dist/runtime/components/fields/BooleanField.d.vue.ts +16 -0
- package/dist/runtime/components/fields/BooleanField.vue +36 -0
- package/dist/runtime/components/fields/BooleanField.vue.d.ts +16 -0
- package/dist/runtime/components/fields/CheckboxGroupField.d.vue.ts +20 -0
- package/dist/runtime/components/fields/CheckboxGroupField.vue +52 -0
- package/dist/runtime/components/fields/CheckboxGroupField.vue.d.ts +20 -0
- package/dist/runtime/components/fields/ColorField.d.vue.ts +19 -0
- package/dist/runtime/components/fields/ColorField.vue +39 -0
- package/dist/runtime/components/fields/ColorField.vue.d.ts +19 -0
- package/dist/runtime/components/fields/DateField.d.vue.ts +18 -0
- package/dist/runtime/components/fields/DateField.vue +39 -0
- package/dist/runtime/components/fields/DateField.vue.d.ts +18 -0
- package/dist/runtime/components/fields/FieldRenderer.d.vue.ts +24 -0
- package/dist/runtime/components/fields/FieldRenderer.vue +135 -0
- package/dist/runtime/components/fields/FieldRenderer.vue.d.ts +24 -0
- package/dist/runtime/components/fields/NumberField.d.vue.ts +20 -0
- package/dist/runtime/components/fields/NumberField.vue +58 -0
- package/dist/runtime/components/fields/NumberField.vue.d.ts +20 -0
- package/dist/runtime/components/fields/RadioField.d.vue.ts +20 -0
- package/dist/runtime/components/fields/RadioField.vue +44 -0
- package/dist/runtime/components/fields/RadioField.vue.d.ts +20 -0
- package/dist/runtime/components/fields/RichTextField.d.vue.ts +20 -0
- package/dist/runtime/components/fields/RichTextField.vue +176 -0
- package/dist/runtime/components/fields/RichTextField.vue.d.ts +20 -0
- package/dist/runtime/components/fields/SectionField.d.vue.ts +20 -0
- package/dist/runtime/components/fields/SectionField.vue +127 -0
- package/dist/runtime/components/fields/SectionField.vue.d.ts +20 -0
- package/dist/runtime/components/fields/SelectField.d.vue.ts +21 -0
- package/dist/runtime/components/fields/SelectField.vue +42 -0
- package/dist/runtime/components/fields/SelectField.vue.d.ts +21 -0
- package/dist/runtime/components/fields/SlugField.d.vue.ts +20 -0
- package/dist/runtime/components/fields/SlugField.vue +35 -0
- package/dist/runtime/components/fields/SlugField.vue.d.ts +20 -0
- package/dist/runtime/components/fields/TabsField.d.vue.ts +19 -0
- package/dist/runtime/components/fields/TabsField.vue +109 -0
- package/dist/runtime/components/fields/TabsField.vue.d.ts +19 -0
- package/dist/runtime/components/fields/TextField.d.vue.ts +22 -0
- package/dist/runtime/components/fields/TextField.vue +56 -0
- package/dist/runtime/components/fields/TextField.vue.d.ts +22 -0
- package/dist/runtime/components/fields/TextareaField.d.vue.ts +20 -0
- package/dist/runtime/components/fields/TextareaField.vue +47 -0
- package/dist/runtime/components/fields/TextareaField.vue.d.ts +20 -0
- package/dist/runtime/components/fields/UrlField.d.vue.ts +17 -0
- package/dist/runtime/components/fields/UrlField.vue +35 -0
- package/dist/runtime/components/fields/UrlField.vue.d.ts +17 -0
- package/dist/runtime/components/ui/EPAccordion.d.vue.ts +26 -0
- package/dist/runtime/components/ui/EPAccordion.vue +64 -0
- package/dist/runtime/components/ui/EPAccordion.vue.d.ts +26 -0
- package/dist/runtime/components/ui/EPAvatar.d.vue.ts +9 -0
- package/dist/runtime/components/ui/EPAvatar.vue +25 -0
- package/dist/runtime/components/ui/EPAvatar.vue.d.ts +9 -0
- package/dist/runtime/components/ui/EPBadge.d.vue.ts +16 -0
- package/dist/runtime/components/ui/EPBadge.vue +17 -0
- package/dist/runtime/components/ui/EPBadge.vue.d.ts +16 -0
- package/dist/runtime/components/ui/EPButton.d.vue.ts +22 -0
- package/dist/runtime/components/ui/EPButton.vue +55 -0
- package/dist/runtime/components/ui/EPButton.vue.d.ts +22 -0
- package/dist/runtime/components/ui/EPCheckbox.d.vue.ts +11 -0
- package/dist/runtime/components/ui/EPCheckbox.vue +21 -0
- package/dist/runtime/components/ui/EPCheckbox.vue.d.ts +11 -0
- package/dist/runtime/components/ui/EPColorPicker.d.vue.ts +19 -0
- package/dist/runtime/components/ui/EPColorPicker.vue +63 -0
- package/dist/runtime/components/ui/EPColorPicker.vue.d.ts +19 -0
- package/dist/runtime/components/ui/EPDialog.d.vue.ts +24 -0
- package/dist/runtime/components/ui/EPDialog.vue +54 -0
- package/dist/runtime/components/ui/EPDialog.vue.d.ts +24 -0
- package/dist/runtime/components/ui/EPDropdownMenu.d.vue.ts +25 -0
- package/dist/runtime/components/ui/EPDropdownMenu.vue +40 -0
- package/dist/runtime/components/ui/EPDropdownMenu.vue.d.ts +25 -0
- package/dist/runtime/components/ui/EPFormField.d.vue.ts +24 -0
- package/dist/runtime/components/ui/EPFormField.vue +62 -0
- package/dist/runtime/components/ui/EPFormField.vue.d.ts +24 -0
- package/dist/runtime/components/ui/EPInputText.d.vue.ts +17 -0
- package/dist/runtime/components/ui/EPInputText.vue +33 -0
- package/dist/runtime/components/ui/EPInputText.vue.d.ts +17 -0
- package/dist/runtime/components/ui/EPLinkEditor.d.vue.ts +16 -0
- package/dist/runtime/components/ui/EPLinkEditor.vue +169 -0
- package/dist/runtime/components/ui/EPLinkEditor.vue.d.ts +16 -0
- package/dist/runtime/components/ui/EPRadioButton.d.vue.ts +16 -0
- package/dist/runtime/components/ui/EPRadioButton.vue +34 -0
- package/dist/runtime/components/ui/EPRadioButton.vue.d.ts +16 -0
- package/dist/runtime/components/ui/EPSelect.d.vue.ts +21 -0
- package/dist/runtime/components/ui/EPSelect.vue +73 -0
- package/dist/runtime/components/ui/EPSelect.vue.d.ts +21 -0
- package/dist/runtime/components/ui/EPSlider.d.vue.ts +16 -0
- package/dist/runtime/components/ui/EPSlider.vue +51 -0
- package/dist/runtime/components/ui/EPSlider.vue.d.ts +16 -0
- package/dist/runtime/components/ui/EPSwitch.d.vue.ts +11 -0
- package/dist/runtime/components/ui/EPSwitch.vue +23 -0
- package/dist/runtime/components/ui/EPSwitch.vue.d.ts +11 -0
- package/dist/runtime/components/ui/EPTextarea.d.vue.ts +12 -0
- package/dist/runtime/components/ui/EPTextarea.vue +18 -0
- package/dist/runtime/components/ui/EPTextarea.vue.d.ts +12 -0
- package/dist/runtime/components/ui/EPToast.d.vue.ts +13 -0
- package/dist/runtime/components/ui/EPToast.vue +60 -0
- package/dist/runtime/components/ui/EPToast.vue.d.ts +13 -0
- package/dist/runtime/components/ui/EPTooltip.d.vue.ts +17 -0
- package/dist/runtime/components/ui/EPTooltip.vue +34 -0
- package/dist/runtime/components/ui/EPTooltip.vue.d.ts +17 -0
- package/dist/runtime/components/ui/form-field-context.d.ts +12 -0
- package/dist/runtime/components/ui/form-field-context.js +1 -0
- package/dist/runtime/composables/useEponyme.d.ts +24 -0
- package/dist/runtime/composables/useEponyme.js +63 -0
- package/dist/runtime/composables/useEponymeAuth.d.ts +16 -0
- package/dist/runtime/composables/useEponymeAuth.js +81 -0
- package/dist/runtime/composables/useEponymeCollection.d.ts +27 -0
- package/dist/runtime/composables/useEponymeCollection.js +44 -0
- package/dist/runtime/composables/useEponymeColorPresets.d.ts +5 -0
- package/dist/runtime/composables/useEponymeColorPresets.js +16 -0
- package/dist/runtime/composables/useEponymeConfig.d.ts +1 -0
- package/dist/runtime/composables/useEponymeConfig.js +4 -0
- package/dist/runtime/composables/useEponymeForm.d.ts +35 -0
- package/dist/runtime/composables/useEponymeForm.js +75 -0
- package/dist/runtime/composables/useEponymeHistory.d.ts +26 -0
- package/dist/runtime/composables/useEponymeHistory.js +24 -0
- package/dist/runtime/composables/useEponymeValidation.d.ts +21 -0
- package/dist/runtime/composables/useEponymeValidation.js +34 -0
- package/dist/runtime/fields/array.d.ts +2 -0
- package/dist/runtime/fields/array.js +3 -0
- package/dist/runtime/fields/boolean.d.ts +2 -0
- package/dist/runtime/fields/boolean.js +3 -0
- package/dist/runtime/fields/checkbox-group.d.ts +2 -0
- package/dist/runtime/fields/checkbox-group.js +3 -0
- package/dist/runtime/fields/color.d.ts +2 -0
- package/dist/runtime/fields/color.js +3 -0
- package/dist/runtime/fields/date.d.ts +3 -0
- package/dist/runtime/fields/date.js +6 -0
- package/dist/runtime/fields/email.d.ts +2 -0
- package/dist/runtime/fields/email.js +3 -0
- package/dist/runtime/fields/image.d.ts +2 -0
- package/dist/runtime/fields/image.js +3 -0
- package/dist/runtime/fields/index.d.ts +37 -0
- package/dist/runtime/fields/index.js +19 -0
- package/dist/runtime/fields/number.d.ts +2 -0
- package/dist/runtime/fields/number.js +3 -0
- package/dist/runtime/fields/radio.d.ts +2 -0
- package/dist/runtime/fields/radio.js +3 -0
- package/dist/runtime/fields/rich-text.d.ts +2 -0
- package/dist/runtime/fields/rich-text.js +3 -0
- package/dist/runtime/fields/section.d.ts +2 -0
- package/dist/runtime/fields/section.js +3 -0
- package/dist/runtime/fields/select.d.ts +2 -0
- package/dist/runtime/fields/select.js +3 -0
- package/dist/runtime/fields/slug.d.ts +2 -0
- package/dist/runtime/fields/slug.js +3 -0
- package/dist/runtime/fields/string.d.ts +2 -0
- package/dist/runtime/fields/string.js +3 -0
- package/dist/runtime/fields/tab.d.ts +2 -0
- package/dist/runtime/fields/tab.js +3 -0
- package/dist/runtime/fields/textarea.d.ts +2 -0
- package/dist/runtime/fields/textarea.js +3 -0
- package/dist/runtime/fields/url.d.ts +2 -0
- package/dist/runtime/fields/url.js +3 -0
- package/dist/runtime/middleware/eponyme-auth.d.ts +2 -0
- package/dist/runtime/middleware/eponyme-auth.js +13 -0
- package/dist/runtime/middleware/eponyme-owner.d.ts +2 -0
- package/dist/runtime/middleware/eponyme-owner.js +7 -0
- package/dist/runtime/pages/EponymeChangePasswordPage.d.vue.ts +3 -0
- package/dist/runtime/pages/EponymeChangePasswordPage.vue +118 -0
- package/dist/runtime/pages/EponymeChangePasswordPage.vue.d.ts +3 -0
- package/dist/runtime/pages/EponymeDetailPage.d.vue.ts +3 -0
- package/dist/runtime/pages/EponymeDetailPage.vue +83 -0
- package/dist/runtime/pages/EponymeDetailPage.vue.d.ts +3 -0
- package/dist/runtime/pages/EponymeIndexPage.d.vue.ts +3 -0
- package/dist/runtime/pages/EponymeIndexPage.vue +51 -0
- package/dist/runtime/pages/EponymeIndexPage.vue.d.ts +3 -0
- package/dist/runtime/pages/EponymeLoginPage.d.vue.ts +3 -0
- package/dist/runtime/pages/EponymeLoginPage.vue +102 -0
- package/dist/runtime/pages/EponymeLoginPage.vue.d.ts +3 -0
- package/dist/runtime/pages/EponymeUsersPage.d.vue.ts +3 -0
- package/dist/runtime/pages/EponymeUsersPage.vue +261 -0
- package/dist/runtime/pages/EponymeUsersPage.vue.d.ts +3 -0
- package/dist/runtime/server/api/eponyme/[name].get.d.ts +4 -0
- package/dist/runtime/server/api/eponyme/[name].get.js +20 -0
- package/dist/runtime/server/api/eponyme/[name].patch.d.ts +11 -0
- package/dist/runtime/server/api/eponyme/[name].patch.js +20 -0
- package/dist/runtime/server/api/eponyme-auth/change-password.post.d.ts +4 -0
- package/dist/runtime/server/api/eponyme-auth/change-password.post.js +21 -0
- package/dist/runtime/server/api/eponyme-auth/login.post.d.ts +4 -0
- package/dist/runtime/server/api/eponyme-auth/login.post.js +12 -0
- package/dist/runtime/server/api/eponyme-auth/logout.post.d.ts +4 -0
- package/dist/runtime/server/api/eponyme-auth/logout.post.js +13 -0
- package/dist/runtime/server/api/eponyme-auth/session.get.d.ts +4 -0
- package/dist/runtime/server/api/eponyme-auth/session.get.js +5 -0
- package/dist/runtime/server/api/eponyme-collections/[path].delete.d.ts +4 -0
- package/dist/runtime/server/api/eponyme-collections/[path].delete.js +11 -0
- package/dist/runtime/server/api/eponyme-collections/[path].get.d.ts +4 -0
- package/dist/runtime/server/api/eponyme-collections/[path].get.js +11 -0
- package/dist/runtime/server/api/eponyme-collections/[path].post.d.ts +7 -0
- package/dist/runtime/server/api/eponyme-collections/[path].post.js +16 -0
- package/dist/runtime/server/api/eponyme-forms/[path].delete.d.ts +6 -0
- package/dist/runtime/server/api/eponyme-forms/[path].delete.js +19 -0
- package/dist/runtime/server/api/eponyme-forms/[path].get.d.ts +4 -0
- package/dist/runtime/server/api/eponyme-forms/[path].get.js +22 -0
- package/dist/runtime/server/api/eponyme-forms/[path].post.d.ts +19 -0
- package/dist/runtime/server/api/eponyme-forms/[path].post.js +36 -0
- package/dist/runtime/server/api/eponyme-history/[path].get.d.ts +4 -0
- package/dist/runtime/server/api/eponyme-history/[path].get.js +11 -0
- package/dist/runtime/server/api/eponyme-history/[path].patch.d.ts +2 -0
- package/dist/runtime/server/api/eponyme-history/[path].patch.js +18 -0
- package/dist/runtime/server/api/eponyme-sitemap.get.d.ts +4 -0
- package/dist/runtime/server/api/eponyme-sitemap.get.js +5 -0
- package/dist/runtime/server/api/eponyme-statuses.get.d.ts +4 -0
- package/dist/runtime/server/api/eponyme-statuses.get.js +7 -0
- package/dist/runtime/server/api/eponyme-users/[id]/reset-password.post.d.ts +5 -0
- package/dist/runtime/server/api/eponyme-users/[id]/reset-password.post.js +12 -0
- package/dist/runtime/server/api/eponyme-users/[id].patch.d.ts +4 -0
- package/dist/runtime/server/api/eponyme-users/[id].patch.js +14 -0
- package/dist/runtime/server/api/eponyme-users/index.get.d.ts +4 -0
- package/dist/runtime/server/api/eponyme-users/index.get.js +7 -0
- package/dist/runtime/server/api/eponyme-users/index.post.d.ts +5 -0
- package/dist/runtime/server/api/eponyme-users/index.post.js +13 -0
- package/dist/runtime/server/plugins/eponyme-sync.d.ts +2 -0
- package/dist/runtime/server/plugins/eponyme-sync.js +14 -0
- package/dist/runtime/server/services/eponyme-auth-service.d.ts +2 -0
- package/dist/runtime/server/services/eponyme-auth-service.js +15 -0
- package/dist/runtime/server/services/eponyme-auth-store.d.ts +119 -0
- package/dist/runtime/server/services/eponyme-auth-store.js +227 -0
- package/dist/runtime/server/services/eponyme-form-service.d.ts +3 -0
- package/dist/runtime/server/services/eponyme-form-service.js +8 -0
- package/dist/runtime/server/services/eponyme-form-store.d.ts +100 -0
- package/dist/runtime/server/services/eponyme-form-store.js +109 -0
- package/dist/runtime/server/services/eponyme-service.d.ts +3 -0
- package/dist/runtime/server/services/eponyme-service.js +8 -0
- package/dist/runtime/server/services/eponyme-store.d.ts +202 -0
- package/dist/runtime/server/services/eponyme-store.js +338 -0
- package/dist/runtime/server/utils/auth.d.ts +11 -0
- package/dist/runtime/server/utils/auth.js +41 -0
- package/dist/runtime/server/utils/eponyme-form.d.ts +14 -0
- package/dist/runtime/server/utils/eponyme-form.js +6 -0
- package/dist/runtime/server/utils/eponyme-sitemap.d.ts +7 -0
- package/dist/runtime/server/utils/eponyme-sitemap.js +7 -0
- package/dist/runtime/server/utils/form-route.d.ts +14 -0
- package/dist/runtime/server/utils/form-route.js +14 -0
- package/dist/runtime/server/utils/password.d.ts +4 -0
- package/dist/runtime/server/utils/password.js +30 -0
- package/dist/runtime/types/auth.d.ts +20 -0
- package/dist/runtime/types/auth.js +7 -0
- package/dist/runtime/types/eponyme-config.d.ts +11 -0
- package/dist/runtime/types/eponyme-navigation.d.ts +6 -0
- package/dist/runtime/types/eponyme-navigation.js +0 -0
- package/dist/runtime/types/eponyme.d.ts +87 -0
- package/dist/runtime/types/eponyme.js +0 -0
- package/dist/runtime/types/field.d.ts +203 -0
- package/dist/runtime/types/field.js +0 -0
- package/dist/runtime/types/index.d.ts +3 -0
- package/dist/runtime/types/index.js +3 -0
- package/dist/runtime/types/nuxt.d.ts +11 -0
- package/dist/runtime/utils/as-record.d.ts +1 -0
- package/dist/runtime/utils/as-record.js +3 -0
- package/dist/runtime/utils/build-eponyme-schema.d.ts +22 -0
- package/dist/runtime/utils/build-eponyme-schema.js +42 -0
- package/dist/runtime/utils/changed-paths.d.ts +6 -0
- package/dist/runtime/utils/changed-paths.js +25 -0
- package/dist/runtime/utils/create-default-eponyme-data.d.ts +5 -0
- package/dist/runtime/utils/create-default-eponyme-data.js +12 -0
- package/dist/runtime/utils/field-path.d.ts +14 -0
- package/dist/runtime/utils/field-path.js +23 -0
- package/dist/runtime/utils/get-eponyme-schemas.d.ts +7 -0
- package/dist/runtime/utils/get-eponyme-schemas.js +33 -0
- package/dist/runtime/utils/get-field-default-value.d.ts +4 -0
- package/dist/runtime/utils/get-field-default-value.js +56 -0
- package/dist/runtime/utils/humanize-label.d.ts +6 -0
- package/dist/runtime/utils/humanize-label.js +3 -0
- package/dist/runtime/utils/initials.d.ts +1 -0
- package/dist/runtime/utils/initials.js +3 -0
- package/dist/runtime/utils/is-field-visible.d.ts +2 -0
- package/dist/runtime/utils/is-field-visible.js +14 -0
- package/dist/runtime/utils/normalize-hex-color.d.ts +8 -0
- package/dist/runtime/utils/normalize-hex-color.js +11 -0
- package/dist/runtime/utils/normalize-slug.d.ts +1 -0
- package/dist/runtime/utils/normalize-slug.js +4 -0
- package/dist/runtime/utils/preview.d.ts +30 -0
- package/dist/runtime/utils/preview.js +30 -0
- package/dist/runtime/utils/validate-eponyme-data.d.ts +10 -0
- package/dist/runtime/utils/validate-eponyme-data.js +204 -0
- package/dist/types.d.mts +11 -0
- package/package.json +96 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { createError, useRoute, useSeoMeta } from "#app";
|
|
3
|
+
import { computed } from "vue";
|
|
4
|
+
import EponymeCollectionPage from "../components/editor/EponymeCollectionPage.vue";
|
|
5
|
+
import EponymeForm from "../components/editor/EponymeForm.vue";
|
|
6
|
+
import EponymeFormPage from "../components/editor/EponymeFormPage.vue";
|
|
7
|
+
import EponymeFolderNav from "../components/editor/EponymeFolderNav.vue";
|
|
8
|
+
import EponymeFolderPage from "../components/editor/EponymeFolderPage.vue";
|
|
9
|
+
import EponymePageNavigation from "../components/editor/EponymePageNavigation.vue";
|
|
10
|
+
import EponymeSidebar from "../components/editor/EponymeSidebar.vue";
|
|
11
|
+
import { useEponymeConfig } from "../composables/useEponymeConfig";
|
|
12
|
+
import { getEponymeCollections, getEponymeForms, getEponymeSchemas } from "../utils/get-eponyme-schemas";
|
|
13
|
+
const route = useRoute();
|
|
14
|
+
const config = useEponymeConfig();
|
|
15
|
+
const eponymeName = computed(() => Array.isArray(route.params.eponyme) ? route.params.eponyme.join("/") : String(route.params.eponyme));
|
|
16
|
+
const schemas = getEponymeSchemas(config);
|
|
17
|
+
const collections = getEponymeCollections(config);
|
|
18
|
+
const forms = getEponymeForms(config);
|
|
19
|
+
const collection = computed(() => collections[eponymeName.value]);
|
|
20
|
+
const form = computed(() => forms[eponymeName.value]);
|
|
21
|
+
const collectionEntry = computed(() => Object.entries(collections).find(([name]) => {
|
|
22
|
+
const prefix = `${name}/`;
|
|
23
|
+
return eponymeName.value.startsWith(prefix) && !eponymeName.value.slice(prefix.length).includes("/");
|
|
24
|
+
}));
|
|
25
|
+
const schema = computed(() => schemas[eponymeName.value] ?? collectionEntry.value?.[1].fields ?? {});
|
|
26
|
+
const entries = Object.keys(schemas);
|
|
27
|
+
const indexPath = computed(() => route.path.slice(0, -(eponymeName.value.length + 1)) || "/");
|
|
28
|
+
const isFolder = computed(() => !schemas[eponymeName.value] && !collection.value && !form.value && !collectionEntry.value && [...Object.keys(schemas), ...Object.keys(collections), ...Object.keys(forms)].some((name) => name.startsWith(`${eponymeName.value}/`)));
|
|
29
|
+
function label(name) {
|
|
30
|
+
return name.replace(/[-_]/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
|
|
31
|
+
}
|
|
32
|
+
useSeoMeta({
|
|
33
|
+
title: () => `${label(eponymeName.value.split("/").at(-1) ?? eponymeName.value)} \xB7 Eponyme`
|
|
34
|
+
});
|
|
35
|
+
if (!schemas[eponymeName.value] && !collection.value && !form.value && !collectionEntry.value && !isFolder.value) throw createError({ statusCode: 404, statusMessage: "Eponyme entry not found." });
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<template>
|
|
39
|
+
<main class="eponyme-root ep:flex ep:min-h-screen ep:flex-col ep:bg-theme-ep ep:font-sans ep:text-text-ep ep:md:flex-row">
|
|
40
|
+
<EponymeSidebar :base-path="indexPath" />
|
|
41
|
+
<div class="ep:w-full">
|
|
42
|
+
<EponymeFolderPage
|
|
43
|
+
v-if="isFolder"
|
|
44
|
+
:base-path="indexPath"
|
|
45
|
+
:folder="eponymeName"
|
|
46
|
+
/>
|
|
47
|
+
<EponymeCollectionPage
|
|
48
|
+
v-else-if="collection"
|
|
49
|
+
:base-path="indexPath"
|
|
50
|
+
:name="eponymeName"
|
|
51
|
+
:definition="collection"
|
|
52
|
+
/>
|
|
53
|
+
<EponymeFormPage
|
|
54
|
+
v-else-if="form"
|
|
55
|
+
:name="eponymeName"
|
|
56
|
+
:definition="form"
|
|
57
|
+
/>
|
|
58
|
+
<template v-else>
|
|
59
|
+
<EponymeFolderNav
|
|
60
|
+
:base-path="indexPath"
|
|
61
|
+
:eponyme="eponymeName"
|
|
62
|
+
class="ep:sticky ep:top-0 ep:z-50"
|
|
63
|
+
/>
|
|
64
|
+
<EponymeForm
|
|
65
|
+
:key="eponymeName"
|
|
66
|
+
:name="eponymeName"
|
|
67
|
+
:schema="schema"
|
|
68
|
+
:readonly-fields="collectionEntry ? [collectionEntry[1].slugField] : []"
|
|
69
|
+
/>
|
|
70
|
+
<EponymePageNavigation
|
|
71
|
+
v-if="!collectionEntry"
|
|
72
|
+
:base-path="indexPath"
|
|
73
|
+
:current="eponymeName"
|
|
74
|
+
:entries="entries"
|
|
75
|
+
/>
|
|
76
|
+
</template>
|
|
77
|
+
</div>
|
|
78
|
+
</main>
|
|
79
|
+
</template>
|
|
80
|
+
|
|
81
|
+
<style scoped>
|
|
82
|
+
:global(body){margin:0}
|
|
83
|
+
</style>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
export default _default;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
export default _default;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { useRoute, useSeoMeta } from "#app";
|
|
3
|
+
import EponymeNavigationLink from "../components/editor/EponymeNavigationLink.vue";
|
|
4
|
+
import EponymeSidebar from "../components/editor/EponymeSidebar.vue";
|
|
5
|
+
import { useEponymeConfig } from "../composables/useEponymeConfig";
|
|
6
|
+
import { getEponymeCollections, getEponymeForms, getEponymeSchemas } from "../utils/get-eponyme-schemas";
|
|
7
|
+
const config = useEponymeConfig();
|
|
8
|
+
const route = useRoute();
|
|
9
|
+
const eponymes = getEponymeSchemas(config);
|
|
10
|
+
const collections = getEponymeCollections(config);
|
|
11
|
+
const forms = getEponymeForms(config);
|
|
12
|
+
const entries = { ...eponymes, ...collections, ...forms };
|
|
13
|
+
useSeoMeta({ title: "Eponyme" });
|
|
14
|
+
function label(name) {
|
|
15
|
+
return name.replace(/[-_]/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
|
|
16
|
+
}
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<template>
|
|
20
|
+
<main class="eponyme-root ep:flex ep:min-h-screen ep:flex-col ep:bg-theme-ep ep:font-sans ep:text-text-ep ep:md:flex-row">
|
|
21
|
+
<EponymeSidebar :base-path="route.path" />
|
|
22
|
+
<section class="ep:mx-auto ep:w-full ep:max-w-3xl ep:px-6 ep:py-8 ep:md:px-10 ep:md:py-12">
|
|
23
|
+
<p class="ep:m-0 ep:text-[11px] ep:font-semibold ep:tracking-widest ep:text-muted-ep ep:uppercase">
|
|
24
|
+
Eponyme
|
|
25
|
+
</p>
|
|
26
|
+
<h1 class="ep:mt-2 ep:text-3xl ep:font-semibold ep:tracking-tight ep:text-white">
|
|
27
|
+
Content entries
|
|
28
|
+
</h1>
|
|
29
|
+
<p class="ep:mt-2 ep:text-sm ep:text-muted-ep">
|
|
30
|
+
Choose the content area you want to update.
|
|
31
|
+
</p>
|
|
32
|
+
<nav
|
|
33
|
+
class="ep:mt-8 ep:grid ep:gap-3 ep:sm:grid-cols-2"
|
|
34
|
+
aria-label="Content entries"
|
|
35
|
+
>
|
|
36
|
+
<EponymeNavigationLink
|
|
37
|
+
v-for="(_, name) in entries"
|
|
38
|
+
:key="name"
|
|
39
|
+
:to="`${route.path.replace(/\/$/, '')}/${name}`"
|
|
40
|
+
:label="label(name.split('/').at(-1) ?? name)"
|
|
41
|
+
:description="collections[name] ? 'Collection' : forms[name] ? 'Form' : void 0"
|
|
42
|
+
variant="card"
|
|
43
|
+
/>
|
|
44
|
+
</nav>
|
|
45
|
+
</section>
|
|
46
|
+
</main>
|
|
47
|
+
</template>
|
|
48
|
+
|
|
49
|
+
<style scoped>
|
|
50
|
+
:global(body){margin:0}
|
|
51
|
+
</style>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
export default _default;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
export default _default;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { navigateTo, useRoute, useRuntimeConfig, useSeoMeta } from "#app";
|
|
3
|
+
import { computed, ref } from "vue";
|
|
4
|
+
import { useEponymeAuth } from "../composables/useEponymeAuth";
|
|
5
|
+
import EPButton from "../components/ui/EPButton.vue";
|
|
6
|
+
import EPFormField from "../components/ui/EPFormField.vue";
|
|
7
|
+
import EPInputText from "../components/ui/EPInputText.vue";
|
|
8
|
+
const route = useRoute();
|
|
9
|
+
const auth = useEponymeAuth();
|
|
10
|
+
const username = ref("");
|
|
11
|
+
const password = ref("");
|
|
12
|
+
const error = ref("");
|
|
13
|
+
const dashboardPath = computed(() => useRuntimeConfig().public.eponyme?.dashboardPath ?? "/__eponyme");
|
|
14
|
+
useSeoMeta({ title: "Sign in \xB7 Eponyme" });
|
|
15
|
+
const existingUser = await auth.refresh();
|
|
16
|
+
if (existingUser)
|
|
17
|
+
await navigateAfterLogin(existingUser.mustChangePassword);
|
|
18
|
+
async function submit() {
|
|
19
|
+
error.value = "";
|
|
20
|
+
try {
|
|
21
|
+
const user = await auth.login(username.value, password.value);
|
|
22
|
+
await navigateAfterLogin(user.mustChangePassword);
|
|
23
|
+
} catch (caught) {
|
|
24
|
+
const fetchError = caught;
|
|
25
|
+
error.value = fetchError.statusMessage ?? "Invalid username or password.";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async function navigateAfterLogin(mustChangePassword) {
|
|
29
|
+
if (mustChangePassword)
|
|
30
|
+
return navigateTo(`${dashboardPath.value}/change-password`);
|
|
31
|
+
const redirect = Array.isArray(route.query.redirect) ? route.query.redirect[0] : route.query.redirect;
|
|
32
|
+
const destination = typeof redirect === "string" && redirect.startsWith(`${dashboardPath.value}/`) ? redirect : dashboardPath.value;
|
|
33
|
+
return navigateTo(destination);
|
|
34
|
+
}
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<template>
|
|
38
|
+
<main class="eponyme-root ep:flex ep:min-h-screen ep:items-center ep:justify-center ep:bg-theme-ep ep:px-6 ep:py-12 ep:font-sans ep:text-text-ep">
|
|
39
|
+
<section class="ep:w-full ep:max-w-sm">
|
|
40
|
+
<p class="ep:m-0 ep:text-[11px] ep:font-semibold ep:tracking-widest ep:text-muted-ep ep:uppercase">
|
|
41
|
+
Eponyme
|
|
42
|
+
</p>
|
|
43
|
+
<h1 class="ep:mt-2 ep:mb-2 ep:text-3xl ep:font-semibold ep:tracking-tight ep:text-white">
|
|
44
|
+
Sign in
|
|
45
|
+
</h1>
|
|
46
|
+
<p class="ep:mt-0 ep:mb-8 ep:text-sm ep:leading-relaxed ep:text-muted-ep">
|
|
47
|
+
Use your Eponyme username and password to open the content dashboard.
|
|
48
|
+
</p>
|
|
49
|
+
<form
|
|
50
|
+
class="ep:grid ep:gap-5"
|
|
51
|
+
@submit.prevent="submit"
|
|
52
|
+
>
|
|
53
|
+
<EPFormField
|
|
54
|
+
id="eponyme-login-username"
|
|
55
|
+
label="Username"
|
|
56
|
+
required
|
|
57
|
+
>
|
|
58
|
+
<EPInputText
|
|
59
|
+
id="eponyme-login-username"
|
|
60
|
+
v-model="username"
|
|
61
|
+
autocomplete="username"
|
|
62
|
+
autofocus
|
|
63
|
+
required
|
|
64
|
+
/>
|
|
65
|
+
</EPFormField>
|
|
66
|
+
<EPFormField
|
|
67
|
+
id="eponyme-login-password"
|
|
68
|
+
label="Password"
|
|
69
|
+
required
|
|
70
|
+
>
|
|
71
|
+
<EPInputText
|
|
72
|
+
id="eponyme-login-password"
|
|
73
|
+
v-model="password"
|
|
74
|
+
type="password"
|
|
75
|
+
autocomplete="current-password"
|
|
76
|
+
required
|
|
77
|
+
/>
|
|
78
|
+
</EPFormField>
|
|
79
|
+
<p
|
|
80
|
+
v-if="error"
|
|
81
|
+
class="ep:m-0 ep:text-sm ep:text-danger-ep"
|
|
82
|
+
role="alert"
|
|
83
|
+
>
|
|
84
|
+
{{ error }}
|
|
85
|
+
</p>
|
|
86
|
+
<EPButton
|
|
87
|
+
type="submit"
|
|
88
|
+
variant="primary"
|
|
89
|
+
:loading="auth.pending.value"
|
|
90
|
+
:disabled="!username || !password"
|
|
91
|
+
class="ep:w-full"
|
|
92
|
+
>
|
|
93
|
+
Sign in
|
|
94
|
+
</EPButton>
|
|
95
|
+
</form>
|
|
96
|
+
</section>
|
|
97
|
+
</main>
|
|
98
|
+
</template>
|
|
99
|
+
|
|
100
|
+
<style scoped>
|
|
101
|
+
:global(body){margin:0}
|
|
102
|
+
</style>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
export default _default;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
export default _default;
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { useRequestFetch, useRoute, useSeoMeta } from "#app";
|
|
3
|
+
import { computed, ref } from "vue";
|
|
4
|
+
import EponymeCopy from "../components/editor/EponymeCopy.vue";
|
|
5
|
+
import EponymeSidebar from "../components/editor/EponymeSidebar.vue";
|
|
6
|
+
import EPButton from "../components/ui/EPButton.vue";
|
|
7
|
+
import EPDialog from "../components/ui/EPDialog.vue";
|
|
8
|
+
import EPFormField from "../components/ui/EPFormField.vue";
|
|
9
|
+
import EPInputText from "../components/ui/EPInputText.vue";
|
|
10
|
+
import EPSelect from "../components/ui/EPSelect.vue";
|
|
11
|
+
import EPSwitch from "../components/ui/EPSwitch.vue";
|
|
12
|
+
import EPTooltip from "../components/ui/EPTooltip.vue";
|
|
13
|
+
import EPAvatar from "../components/ui/EPAvatar.vue";
|
|
14
|
+
useSeoMeta({ title: "Users \xB7 Eponyme" });
|
|
15
|
+
const route = useRoute();
|
|
16
|
+
const requestFetch = useRequestFetch();
|
|
17
|
+
const users = ref([]);
|
|
18
|
+
const pending = ref(true);
|
|
19
|
+
const error = ref("");
|
|
20
|
+
const createOpen = ref(false);
|
|
21
|
+
const username = ref("");
|
|
22
|
+
const role = ref("editor");
|
|
23
|
+
const temporaryCredentials = ref();
|
|
24
|
+
const basePath = computed(() => route.path.replace(/\/users\/?$/, ""));
|
|
25
|
+
const roleOptions = [
|
|
26
|
+
{ label: "Viewer", value: "viewer" },
|
|
27
|
+
{ label: "Editor", value: "editor" },
|
|
28
|
+
{ label: "Owner", value: "owner" }
|
|
29
|
+
];
|
|
30
|
+
await loadUsers();
|
|
31
|
+
async function loadUsers() {
|
|
32
|
+
pending.value = true;
|
|
33
|
+
try {
|
|
34
|
+
const response = await requestFetch("/api/eponyme-users", { cache: "no-store" });
|
|
35
|
+
users.value = response.users;
|
|
36
|
+
} finally {
|
|
37
|
+
pending.value = false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async function createUser() {
|
|
41
|
+
error.value = "";
|
|
42
|
+
try {
|
|
43
|
+
const result = await requestFetch("/api/eponyme-users", {
|
|
44
|
+
method: "POST",
|
|
45
|
+
body: { username: username.value, role: role.value }
|
|
46
|
+
});
|
|
47
|
+
users.value.push(result.user);
|
|
48
|
+
temporaryCredentials.value = result;
|
|
49
|
+
createOpen.value = false;
|
|
50
|
+
username.value = "";
|
|
51
|
+
role.value = "editor";
|
|
52
|
+
} catch (caught) {
|
|
53
|
+
error.value = caught.statusMessage ?? "Unable to create user.";
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async function updateUser(user, changes) {
|
|
57
|
+
error.value = "";
|
|
58
|
+
try {
|
|
59
|
+
const response = await requestFetch(`/api/eponyme-users/${user.id}`, {
|
|
60
|
+
method: "PATCH",
|
|
61
|
+
body: changes
|
|
62
|
+
});
|
|
63
|
+
replaceUser(response.user);
|
|
64
|
+
} catch (caught) {
|
|
65
|
+
error.value = caught.statusMessage ?? "Unable to update user.";
|
|
66
|
+
await loadUsers();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async function resetPassword(user) {
|
|
70
|
+
if (!confirm(`Reset the password for ${user.username}?`)) return;
|
|
71
|
+
error.value = "";
|
|
72
|
+
try {
|
|
73
|
+
const result = await requestFetch(`/api/eponyme-users/${user.id}/reset-password`, {
|
|
74
|
+
method: "POST"
|
|
75
|
+
});
|
|
76
|
+
replaceUser(result.user);
|
|
77
|
+
temporaryCredentials.value = result;
|
|
78
|
+
} catch (caught) {
|
|
79
|
+
error.value = caught.statusMessage ?? "Unable to reset password.";
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function replaceUser(user) {
|
|
83
|
+
users.value = users.value.map((item) => item.id === user.id ? user : item);
|
|
84
|
+
}
|
|
85
|
+
</script>
|
|
86
|
+
|
|
87
|
+
<template>
|
|
88
|
+
<main class="eponyme-root ep:flex ep:min-h-screen ep:flex-col ep:bg-theme-ep ep:font-sans ep:text-text-ep ep:md:flex-row">
|
|
89
|
+
<EponymeSidebar :base-path="basePath" />
|
|
90
|
+
<section class="ep:mx-auto ep:w-full ep:max-w-4xl ep:px-6 ep:py-8 ep:md:px-10 ep:md:py-12">
|
|
91
|
+
<header class="ep:flex ep:flex-wrap ep:items-end ep:justify-between ep:gap-4">
|
|
92
|
+
<div>
|
|
93
|
+
<p class="ep:m-0 ep:text-[11px] ep:font-semibold ep:tracking-widest ep:text-muted-ep ep:uppercase">
|
|
94
|
+
Access
|
|
95
|
+
</p>
|
|
96
|
+
<h1 class="ep:mt-2 ep:mb-0 ep:text-3xl ep:font-semibold ep:tracking-tight ep:text-white">
|
|
97
|
+
Users
|
|
98
|
+
</h1>
|
|
99
|
+
<p class="ep:mt-2 ep:mb-0 ep:text-sm ep:text-muted-ep">
|
|
100
|
+
Manage dashboard access and content permissions.
|
|
101
|
+
</p>
|
|
102
|
+
</div>
|
|
103
|
+
<EPButton
|
|
104
|
+
variant="primary"
|
|
105
|
+
@click="createOpen = true"
|
|
106
|
+
>
|
|
107
|
+
Add user
|
|
108
|
+
</EPButton>
|
|
109
|
+
</header>
|
|
110
|
+
|
|
111
|
+
<p
|
|
112
|
+
v-if="error"
|
|
113
|
+
class="ep:mt-6 ep:rounded-xl ep:bg-danger-ep/10 ep:p-4 ep:text-sm ep:text-danger-ep"
|
|
114
|
+
role="alert"
|
|
115
|
+
>
|
|
116
|
+
{{ error }}
|
|
117
|
+
</p>
|
|
118
|
+
<p
|
|
119
|
+
v-if="pending"
|
|
120
|
+
class="ep:mt-8 ep:text-sm ep:text-muted-ep"
|
|
121
|
+
>
|
|
122
|
+
Loading users…
|
|
123
|
+
</p>
|
|
124
|
+
<div
|
|
125
|
+
v-else
|
|
126
|
+
class="ep:mt-8 ep:grid ep:gap-3"
|
|
127
|
+
>
|
|
128
|
+
<article
|
|
129
|
+
v-for="user in users"
|
|
130
|
+
:key="user.id"
|
|
131
|
+
class="ep:grid ep:gap-4 ep:rounded-xl ep:bg-selected-ep/50 ep:p-4 ep:sm:grid-cols-[minmax(0,1fr)_10rem_auto_auto] ep:sm:items-center"
|
|
132
|
+
>
|
|
133
|
+
<div class="ep:flex ep:min-w-0 ep:items-center ep:gap-3">
|
|
134
|
+
<EPAvatar :fallback="user.username" />
|
|
135
|
+
<div class="ep:min-w-0">
|
|
136
|
+
<p class="ep:m-0 ep:truncate ep:text-sm ep:font-semibold ep:text-white">
|
|
137
|
+
{{ user.username }}
|
|
138
|
+
</p>
|
|
139
|
+
<p
|
|
140
|
+
v-if="user.mustChangePassword"
|
|
141
|
+
class="ep:m-0 ep:mt-1 ep:text-xs ep:text-muted-ep"
|
|
142
|
+
>
|
|
143
|
+
Password change required
|
|
144
|
+
</p>
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
147
|
+
<EPSelect
|
|
148
|
+
size="sm"
|
|
149
|
+
:model-value="user.role"
|
|
150
|
+
:options="roleOptions"
|
|
151
|
+
aria-label="Role"
|
|
152
|
+
@update:model-value="updateUser(user, { role: $event })"
|
|
153
|
+
/>
|
|
154
|
+
<EPButton
|
|
155
|
+
size="sm"
|
|
156
|
+
@click="resetPassword(user)"
|
|
157
|
+
>
|
|
158
|
+
Reset password
|
|
159
|
+
</EPButton>
|
|
160
|
+
<EPTooltip :content="user.active ? 'Active' : 'Disabled'">
|
|
161
|
+
<EPSwitch
|
|
162
|
+
:model-value="user.active"
|
|
163
|
+
:aria-label="user.active ? `Deactivate ${user.username}` : `Activate ${user.username}`"
|
|
164
|
+
@update:model-value="updateUser(user, { active: $event })"
|
|
165
|
+
/>
|
|
166
|
+
</EPTooltip>
|
|
167
|
+
</article>
|
|
168
|
+
</div>
|
|
169
|
+
</section>
|
|
170
|
+
|
|
171
|
+
<EPDialog
|
|
172
|
+
:open="createOpen"
|
|
173
|
+
title="Add user"
|
|
174
|
+
description="A temporary password will be generated and shown once."
|
|
175
|
+
@update:open="createOpen = $event"
|
|
176
|
+
>
|
|
177
|
+
<form
|
|
178
|
+
class="ep:grid ep:gap-4"
|
|
179
|
+
@submit.prevent="createUser"
|
|
180
|
+
>
|
|
181
|
+
<EPFormField
|
|
182
|
+
id="eponyme-user-username"
|
|
183
|
+
label="Username"
|
|
184
|
+
description="3 to 50 letters, numbers, dots, underscores or hyphens."
|
|
185
|
+
required
|
|
186
|
+
>
|
|
187
|
+
<EPInputText
|
|
188
|
+
id="eponyme-user-username"
|
|
189
|
+
v-model="username"
|
|
190
|
+
autocomplete="off"
|
|
191
|
+
required
|
|
192
|
+
/>
|
|
193
|
+
</EPFormField>
|
|
194
|
+
<EPFormField
|
|
195
|
+
id="eponyme-user-role"
|
|
196
|
+
label="Role"
|
|
197
|
+
required
|
|
198
|
+
>
|
|
199
|
+
<EPSelect
|
|
200
|
+
id="eponyme-user-role"
|
|
201
|
+
v-model="role"
|
|
202
|
+
:options="roleOptions"
|
|
203
|
+
/>
|
|
204
|
+
</EPFormField>
|
|
205
|
+
<div class="ep:flex ep:justify-end ep:gap-2">
|
|
206
|
+
<EPButton @click="createOpen = false">
|
|
207
|
+
Cancel
|
|
208
|
+
</EPButton>
|
|
209
|
+
<EPButton
|
|
210
|
+
type="submit"
|
|
211
|
+
variant="primary"
|
|
212
|
+
:disabled="!username"
|
|
213
|
+
>
|
|
214
|
+
Create user
|
|
215
|
+
</EPButton>
|
|
216
|
+
</div>
|
|
217
|
+
</form>
|
|
218
|
+
</EPDialog>
|
|
219
|
+
|
|
220
|
+
<EPDialog
|
|
221
|
+
:open="Boolean(temporaryCredentials)"
|
|
222
|
+
title="Temporary credentials"
|
|
223
|
+
description="Copy this password now. It cannot be displayed again."
|
|
224
|
+
@update:open="!$event && (temporaryCredentials = void 0)"
|
|
225
|
+
>
|
|
226
|
+
<div v-if="temporaryCredentials">
|
|
227
|
+
<dl class="ep:grid ep:gap-3">
|
|
228
|
+
<div>
|
|
229
|
+
<dt class="ep:text-xs ep:text-muted-ep">
|
|
230
|
+
Username
|
|
231
|
+
</dt>
|
|
232
|
+
<dd class="ep:mt-1 ep:mb-0">
|
|
233
|
+
<EponymeCopy
|
|
234
|
+
:value="temporaryCredentials.user.username"
|
|
235
|
+
label="Copy"
|
|
236
|
+
/>
|
|
237
|
+
</dd>
|
|
238
|
+
</div>
|
|
239
|
+
<div>
|
|
240
|
+
<dt class="ep:text-xs ep:text-muted-ep">
|
|
241
|
+
Temporary password
|
|
242
|
+
</dt>
|
|
243
|
+
<dd class="ep:mt-1 ep:mb-0">
|
|
244
|
+
<EponymeCopy
|
|
245
|
+
:value="temporaryCredentials.temporaryPassword"
|
|
246
|
+
label="Copy"
|
|
247
|
+
/>
|
|
248
|
+
</dd>
|
|
249
|
+
</div>
|
|
250
|
+
</dl>
|
|
251
|
+
<p class="ep:mt-4 ep:mb-0 ep:text-xs ep:leading-relaxed ep:text-muted-ep">
|
|
252
|
+
The user must replace it immediately after signing in.
|
|
253
|
+
</p>
|
|
254
|
+
</div>
|
|
255
|
+
</EPDialog>
|
|
256
|
+
</main>
|
|
257
|
+
</template>
|
|
258
|
+
|
|
259
|
+
<style scoped>
|
|
260
|
+
:global(body){margin:0}
|
|
261
|
+
</style>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
export default _default;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createError, defineEventHandler, getQuery, getRequestURL, setResponseHeader } from "h3";
|
|
2
|
+
import { useEponymeService } from "../../services/eponyme-service.js";
|
|
3
|
+
import { requireEponymeUser } from "../../utils/auth.js";
|
|
4
|
+
function readVersion(raw) {
|
|
5
|
+
if (raw === "draft") return "draft";
|
|
6
|
+
const id = Number(raw);
|
|
7
|
+
return Number.isSafeInteger(id) && id > 0 ? id : "published";
|
|
8
|
+
}
|
|
9
|
+
export default defineEventHandler(async (event) => {
|
|
10
|
+
const name = decodeURIComponent(getRequestURL(event).pathname.replace(/^\/api\/eponyme\//, ""));
|
|
11
|
+
const requestedVersion = getQuery(event).version;
|
|
12
|
+
const version = readVersion(requestedVersion);
|
|
13
|
+
if (version !== "published") {
|
|
14
|
+
await requireEponymeUser(event);
|
|
15
|
+
setResponseHeader(event, "Cache-Control", "no-store");
|
|
16
|
+
}
|
|
17
|
+
const result = name ? await useEponymeService().getResult(name, version) : void 0;
|
|
18
|
+
if (!result) throw createError({ statusCode: 404, statusMessage: "Eponyme entry not found." });
|
|
19
|
+
return requestedVersion ? result : { data: result.data };
|
|
20
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<(import("../../services/eponyme-store.js").EponymeResult & {
|
|
2
|
+
errors?: never;
|
|
3
|
+
conflict?: never;
|
|
4
|
+
}) | {
|
|
5
|
+
errors: import("../../../utils/validate-eponyme-data.js").ValidationErrors;
|
|
6
|
+
data?: undefined;
|
|
7
|
+
} | {
|
|
8
|
+
data: Record<string, unknown>;
|
|
9
|
+
errors?: undefined;
|
|
10
|
+
}>>;
|
|
11
|
+
export default _default;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createError, defineEventHandler, getQuery, getRequestURL, readBody, setResponseStatus } from "h3";
|
|
2
|
+
import { useEponymeService } from "../../services/eponyme-service.js";
|
|
3
|
+
import { assertEponymeMutationOrigin, requireEponymeUser } from "../../utils/auth.js";
|
|
4
|
+
export default defineEventHandler(async (event) => {
|
|
5
|
+
assertEponymeMutationOrigin(event);
|
|
6
|
+
const user = await requireEponymeUser(event, { roles: ["editor", "owner"] });
|
|
7
|
+
const name = decodeURIComponent(getRequestURL(event).pathname.replace(/^\/api\/eponyme\//, ""));
|
|
8
|
+
if (!name) throw createError({ statusCode: 404, statusMessage: "Eponyme entry not found." });
|
|
9
|
+
const requestedAction = getQuery(event).action;
|
|
10
|
+
const action = requestedAction === "draft" ? "draft" : "publish";
|
|
11
|
+
const result = await useEponymeService().patch(name, await readBody(event), action, user.id);
|
|
12
|
+
if (!result) throw createError({ statusCode: 404, statusMessage: "Eponyme entry not found." });
|
|
13
|
+
if ("conflict" in result && result.conflict)
|
|
14
|
+
throw createError({ statusCode: 409, message: "This entry was changed by someone else. Reload the page to get the latest version." });
|
|
15
|
+
if (result.errors) {
|
|
16
|
+
setResponseStatus(event, 422);
|
|
17
|
+
return { errors: result.errors };
|
|
18
|
+
}
|
|
19
|
+
return requestedAction ? result : { data: result.data };
|
|
20
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createError, defineEventHandler, readBody } from "h3";
|
|
2
|
+
import { useEponymeAuthService } from "../../services/eponyme-auth-service.js";
|
|
3
|
+
import {
|
|
4
|
+
assertEponymeMutationOrigin,
|
|
5
|
+
requireEponymeUser,
|
|
6
|
+
setEponymeSessionCookie
|
|
7
|
+
} from "../../utils/auth.js";
|
|
8
|
+
export default defineEventHandler(async (event) => {
|
|
9
|
+
assertEponymeMutationOrigin(event);
|
|
10
|
+
const user = await requireEponymeUser(event, { allowPasswordChangeRequired: true });
|
|
11
|
+
const body = await readBody(event);
|
|
12
|
+
const result = await useEponymeAuthService().changePassword(
|
|
13
|
+
user.id,
|
|
14
|
+
body?.currentPassword,
|
|
15
|
+
body?.newPassword
|
|
16
|
+
);
|
|
17
|
+
if (!result.session)
|
|
18
|
+
throw createError({ statusCode: 422, statusMessage: result.error ?? "Unable to change password." });
|
|
19
|
+
setEponymeSessionCookie(event, result.session.token, result.session.expiresAt);
|
|
20
|
+
return { user: result.session.user };
|
|
21
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createError, defineEventHandler, readBody } from "h3";
|
|
2
|
+
import { useEponymeAuthService } from "../../services/eponyme-auth-service.js";
|
|
3
|
+
import { assertEponymeMutationOrigin, setEponymeSessionCookie } from "../../utils/auth.js";
|
|
4
|
+
export default defineEventHandler(async (event) => {
|
|
5
|
+
assertEponymeMutationOrigin(event);
|
|
6
|
+
const body = await readBody(event);
|
|
7
|
+
const result = await useEponymeAuthService().login(body?.username, body?.password);
|
|
8
|
+
if (!result.ok)
|
|
9
|
+
throw createError({ statusCode: 401, statusMessage: "Invalid username or password." });
|
|
10
|
+
setEponymeSessionCookie(event, result.session.token, result.session.expiresAt);
|
|
11
|
+
return { user: result.session.user };
|
|
12
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { defineEventHandler, getCookie } from "h3";
|
|
2
|
+
import { useEponymeAuthService } from "../../services/eponyme-auth-service.js";
|
|
3
|
+
import {
|
|
4
|
+
assertEponymeMutationOrigin,
|
|
5
|
+
clearEponymeSessionCookie,
|
|
6
|
+
EPONYME_SESSION_COOKIE
|
|
7
|
+
} from "../../utils/auth.js";
|
|
8
|
+
export default defineEventHandler(async (event) => {
|
|
9
|
+
assertEponymeMutationOrigin(event);
|
|
10
|
+
await useEponymeAuthService().logout(getCookie(event, EPONYME_SESSION_COOKIE));
|
|
11
|
+
clearEponymeSessionCookie(event);
|
|
12
|
+
return { loggedOut: true };
|
|
13
|
+
});
|