760 lines
29 KiB
JavaScript
760 lines
29 KiB
JavaScript
import { computed, inject, ref } from "vue";
|
|
import { useRoute, useRouter } from "vue-router";
|
|
import { build_url } from "../composables/datatables";
|
|
import { storeToRefs } from "pinia";
|
|
import {
|
|
$__,
|
|
$__x,
|
|
$__n,
|
|
$__nx,
|
|
$__p,
|
|
$__px,
|
|
$__np,
|
|
$__npx,
|
|
} from "@koha-vue/i18n";
|
|
|
|
/**
|
|
* A composable that provides utilities for the resource component.
|
|
*
|
|
* The utilities provided by this composable are documented individually below.
|
|
*
|
|
* @param {Object} resourceConfig - The resource component instance.
|
|
* This can take in the following parameters
|
|
* REQUIRED:
|
|
* @param {String} resourceConfig.resourceName - The name of the resource.
|
|
* @param {String} resourceConfig.idAttr - The name of the id attribute of the resource.
|
|
* @param {String} resourceConfig.nameAttr - The name attribute of the resource.
|
|
* @param {String} resourceConfig.components - An object containing the names of the components ("show", "add", "list", "edit")
|
|
* @param {Object} resourceConfig.i18n - The i18n object.
|
|
* @param {Object} resourceConfig.apiClient - The API client for the resource.
|
|
* @param {Object} resourceConfig.table - Contains the table configuration.
|
|
* @param {String} resourceConfig.table.resourceTableUrl - The URL to the resource table.
|
|
* @param {Array} resourceConfig.resourceAttrs - An array of attributes that relate to the resource's properties and how they should appear in the form/show/list components.
|
|
* @param {Object} resourceConfig.props - The props passed to the resource component.
|
|
* OPTIONAL:
|
|
* @param {String} resourceConfig.moduleStore - The name of the module store that holds resource related data (authorised values, permissions etc)
|
|
* @param {Boolean} resourceConfig.table.addAdditionalFilters - A flag to indicate whether to add filters to the list component for the datatable.
|
|
* @param {Object} resourceConfig.table.filters - The table filters for the resource. Follows the format for the resourceAttrs parameter.
|
|
* @param {Function} resourceConfig.afterResourceFetch - A function to call after the resource is fetched. This can be used to edit resource data or fetch additional data
|
|
* @param {Boolean} resourceConfig.embedded - A flag to indicate whether the resource is actually being used as a child component of another resource e.g. embedding a list of agreements into EBSCO package agreements
|
|
* @param {String} resourceConfig.extendedAttributesResourceType - The resource type for extended attributes, if applicable.
|
|
* @param {String} resourceConfig.extendedAttributesFieldGroup - The field group that you would like the additional fields to be displayed in.
|
|
* @param {Function} resourceConfig.defaultToolbarButtons - A function to amend default buttons in the toolbar.
|
|
* @param {Function} resourceConfig.additionalToolbarButtons - A function to add additional buttons to the toolbar.
|
|
* @param {String} resourceConfig.formGroupsDisplayMode - The display mode for the form groups if not the default. Can be one of the following: "accordion", "tabs".
|
|
* @param {Array} resourceConfig.stickyToolbar - The names of the components with a toolbar that should be sticky.
|
|
* @param {Array} resourceConfig.navigationOnFormSave - The name of the component that should be navigated to when saving the resource creation/edit form. Defaults to the show component
|
|
*
|
|
* @return {Object} An object containing the utilities provided by this composable.
|
|
*/
|
|
export function useBaseResource(resourceConfig) {
|
|
const router = useRouter();
|
|
const route = useRoute();
|
|
const {
|
|
setConfirmationDialog,
|
|
setMessage,
|
|
setError,
|
|
setWarning,
|
|
updateConfirmationDialogInputs,
|
|
} = inject("mainStore");
|
|
const navigationStore = inject("navigationStore");
|
|
const { breadcrumbMetadata } = storeToRefs(navigationStore);
|
|
|
|
const moduleStoreUtils = {};
|
|
if (resourceConfig.moduleStore) {
|
|
const moduleStore = inject(resourceConfig.moduleStore);
|
|
const { get_lib_from_av, map_av_dt_filter, isUserPermitted } =
|
|
moduleStore;
|
|
const { authorisedValues, userPermissions } = storeToRefs(moduleStore);
|
|
|
|
if (authorisedValues) {
|
|
moduleStoreUtils.get_lib_from_av = get_lib_from_av;
|
|
moduleStoreUtils.map_av_dt_filter = map_av_dt_filter;
|
|
moduleStoreUtils.authorisedValues = authorisedValues.value;
|
|
}
|
|
|
|
if (userPermissions) {
|
|
moduleStoreUtils.userPermissions = userPermissions.value;
|
|
moduleStoreUtils.isUserPermitted = isUserPermitted;
|
|
}
|
|
}
|
|
|
|
let i18n = resourceConfig.i18n;
|
|
|
|
/**
|
|
**********************************************************************
|
|
* TOOLBAR RELATED METHODS
|
|
**********************************************************************
|
|
*/
|
|
|
|
/**
|
|
* A function that returns a set of buttons to display in the toolbar, based on the current resource and component.
|
|
* The function takes two arguments: the resource and the component.
|
|
* It returns an array of buttons. The buttons are a combination of the default buttons and the additional buttons.
|
|
* The default buttons are defined in the defaultToolbarButtons function and the additional buttons are defined in the
|
|
* additionalToolbarButtons function at the resource level.
|
|
*
|
|
* @param {Object} resource The current resource
|
|
* @param {String} component The current component
|
|
* @return {Array<Object>} An array of buttons
|
|
*/
|
|
const toolbarButtons = computed(() => {
|
|
return (resource, component, componentData) => {
|
|
let defaultButtons = defaultToolbarButtons(resource);
|
|
defaultButtons = resourceConfig.hasOwnProperty(
|
|
"defaultToolbarButtons"
|
|
)
|
|
? resourceConfig.defaultToolbarButtons(
|
|
defaultButtons,
|
|
resource || {}
|
|
)
|
|
: defaultButtons;
|
|
const additionalButtons = resourceConfig.hasOwnProperty(
|
|
"additionalToolbarButtons"
|
|
)
|
|
? resourceConfig.additionalToolbarButtons(
|
|
resource || {},
|
|
componentData
|
|
)
|
|
: additionalToolbarButtons(resource, componentData);
|
|
|
|
//FIXME: we need to check that no indexes match between the default buttons and additional buttons
|
|
// If we add to the default buttons in future it could mess up indexing
|
|
|
|
return [
|
|
...(defaultButtons[component] || []),
|
|
...(additionalButtons[component] || []).filter(
|
|
button => Object.keys(button).length > 0
|
|
),
|
|
].sort((a, b) => a.index - b.index);
|
|
};
|
|
});
|
|
|
|
/**
|
|
* Gets the list of default buttons to add to the toolbar, for each view: list, show, edit
|
|
* It can be overridden at the resource level if the default buttons are not required
|
|
*
|
|
* @return {Object} keys must be "list", "show" or "edit", values are functions.
|
|
*/
|
|
const defaultToolbarButtons = resource => {
|
|
return {
|
|
list: [
|
|
{
|
|
action: "add",
|
|
onClick: () => goToResourceAdd(),
|
|
title: i18n.newLabel,
|
|
index: 0,
|
|
},
|
|
],
|
|
show: [
|
|
{
|
|
action: "edit",
|
|
onClick: () => goToResourceEdit(resource),
|
|
title: $__("Edit"),
|
|
index: 0,
|
|
},
|
|
{
|
|
action: "delete",
|
|
onClick: () => doResourceDelete(resource),
|
|
title: $__("Delete"),
|
|
index: 1,
|
|
},
|
|
],
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Returns a default empty set of additional buttons
|
|
* Additional buttons should be added in the resource specific component
|
|
*
|
|
* @returns {Object}
|
|
*/
|
|
const additionalToolbarButtons = () => {
|
|
return {
|
|
list: [],
|
|
show: [],
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Navigates to the creation page of the given resource.
|
|
*
|
|
* @return {void}
|
|
*/
|
|
const goToResourceAdd = () => {
|
|
router.push({
|
|
name: resourceConfig.components.add,
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Navigates to the edit page of the given resource.
|
|
*
|
|
* @param {Object} resource - The resource to navigate to (optional)
|
|
* @return {void}
|
|
*/
|
|
const goToResourceEdit = resource => {
|
|
router.push({
|
|
name: resourceConfig.components.edit,
|
|
params: {
|
|
[resourceConfig.idAttr]: resource
|
|
? resource[resourceConfig.idAttr]
|
|
: resourceConfig.newResource[resourceConfig.idAttr],
|
|
},
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Navigates to the show page of the given resource.
|
|
*
|
|
* @param {Object} [resource] - The resource to navigate to
|
|
* @param {DataTable} [dt] - The DataTable (optional)
|
|
* @param {Event} [event] - The event to prevent default handling of (optional)
|
|
* @return {void}
|
|
*/
|
|
const goToResourceShow = (resource, dt, event) => {
|
|
event?.preventDefault();
|
|
router.push({
|
|
name: resourceConfig.components.show,
|
|
params: {
|
|
[resourceConfig.idAttr]: resource[resourceConfig.idAttr],
|
|
},
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Navigates to the list page of the given resource.
|
|
*
|
|
* @return {void}
|
|
*/
|
|
const goToResourceList = () => {
|
|
router.push({
|
|
name: resourceConfig.components.list,
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Resource deletion handler.
|
|
* Accepts an optional callback function to run after deletion.
|
|
* If no callback is provided, does the following:
|
|
* - If deleting from show component, navigates to resource list component.
|
|
* - If deleting from resource list component, redraws the table.
|
|
*
|
|
* @param {Object} resource - The resource to delete (optional)
|
|
* @param {Object} callback - Callback to call after deletion (optional)
|
|
* @return {void}
|
|
*/
|
|
const doResourceDelete = (resource, callback) => {
|
|
let resourceId = resource
|
|
? resource[resourceConfig.idAttr]
|
|
: resourceConfig.newResource[resourceConfig.idAttr];
|
|
let resourceName = resource
|
|
? resource[resourceConfig.nameAttr]
|
|
: resourceConfig.newResource[resourceConfig.nameAttr];
|
|
|
|
setConfirmationDialog(
|
|
{
|
|
title: i18n.deleteConfirmationMessage,
|
|
message: resourceName,
|
|
accept_label: $__("Yes, delete"),
|
|
cancel_label: $__("No, do not delete"),
|
|
},
|
|
() => {
|
|
resourceConfig.apiClient.delete(resourceId).then(
|
|
success => {
|
|
setMessage(
|
|
i18n.deleteSuccessMessage.format(resourceName),
|
|
true
|
|
);
|
|
if (typeof callback === "function") {
|
|
callback();
|
|
} else {
|
|
if (resourceConfig.props.routeAction === "list") {
|
|
callback.ajax.reload();
|
|
} else {
|
|
goToResourceList();
|
|
}
|
|
}
|
|
},
|
|
error => {}
|
|
);
|
|
}
|
|
);
|
|
};
|
|
|
|
/**
|
|
* Emits the 'select-resource' event with the id of the provided resource.
|
|
*
|
|
* @param {Object} resource - The resource object containing the id attribute.
|
|
* @param {Object} dt - DataTables instance (not used in this function).
|
|
* @param {Event} event - The event object (not used in this function).
|
|
*/
|
|
|
|
const doResourceSelect = (resource, dt, event) => {
|
|
resourceConfig.$emit(
|
|
"select-resource",
|
|
resource[resourceConfig.idAttr]
|
|
);
|
|
};
|
|
|
|
/*
|
|
**********************************************************************
|
|
* DATATABLES RELATED METHODS
|
|
**********************************************************************
|
|
*/
|
|
|
|
/**
|
|
* Return the URL for the resource table.
|
|
*
|
|
* @return {string}
|
|
*/
|
|
const getResourceTableUrl = () => {
|
|
return resourceConfig.table.resourceTableUrl;
|
|
};
|
|
|
|
/**
|
|
* Generates the URL for the show page of the given resource.
|
|
*
|
|
* @param {Object} resource - The resource to generate the URL for
|
|
* @return {string} The URL for the show page of the given resource
|
|
*/
|
|
const getResourceShowURL = id => {
|
|
return router.resolve({
|
|
name: resourceConfig.components.show,
|
|
params: { [resourceConfig.idAttr]: id },
|
|
}).href;
|
|
};
|
|
|
|
/**
|
|
* Builds an object of filter name-value pairs based on the provided
|
|
* query object and filterData ('filters' by default).
|
|
*
|
|
* Iterates over the query object keys and updates the filterOptions
|
|
* object with the new values. If a filter name is not found in
|
|
* filterOptions, it is added.
|
|
*
|
|
* @param {Object} query - The query object (taken from the URL params)containing the filter values.
|
|
* @param {Array} filterData - The array of filter objects (optional).
|
|
* @return {Object}
|
|
*/
|
|
const getFilterValues = (query, filterData = []) => {
|
|
const filters = filterData.length
|
|
? filterData
|
|
: resourceConfig.table.additionalFilters
|
|
? resourceConfig.table.additionalFilters
|
|
: [];
|
|
const filterOptions = filters.reduce((acc, filter) => {
|
|
acc[filter.name] = filter.value;
|
|
return acc;
|
|
}, {});
|
|
|
|
Object.keys(query).forEach(key => {
|
|
if (
|
|
filterOptions.hasOwnProperty(key) &&
|
|
query[key] !== filterOptions[key]
|
|
) {
|
|
filterOptions[key] = query[key];
|
|
}
|
|
if (!filterOptions.hasOwnProperty(key)) {
|
|
filterOptions[key] = query[key];
|
|
}
|
|
});
|
|
return filterOptions;
|
|
};
|
|
|
|
/**
|
|
* Gets the label to display before the filters in the List component
|
|
* This is a default method that returns an empty string.
|
|
* It can be overridden at the resource level if filters are required
|
|
*
|
|
* @return {String} The label
|
|
*/
|
|
const getTableFilterFormElementsLabel = () => {
|
|
return "";
|
|
};
|
|
|
|
/**
|
|
* Gets the array of filters for the table, if required.
|
|
* This is a default method that returns an empty array.
|
|
* It can be overridden at the resource level if filters are required
|
|
*
|
|
* @return {Array} The array of filters for the table.
|
|
*/
|
|
const getTableFilterFormElements = () => {
|
|
return [];
|
|
};
|
|
|
|
/*
|
|
**********************************************************************
|
|
* RESOURCE DISPLAY RELATED METHODS
|
|
**********************************************************************
|
|
*/
|
|
|
|
/**
|
|
* A function that can be used to add additional content to the show view
|
|
* of a resource. The function should return an array of attributes such as those in 'resourceAttrs' in the module specific resources
|
|
*
|
|
* @returns {Array}
|
|
*/
|
|
const appendToShow = () => {
|
|
return [];
|
|
};
|
|
|
|
/**
|
|
* This method takes a component name (e.g. 'Form' or 'Show') and an optional resource object
|
|
* and returns an array of grouped objects that determine which fields should be grouped together
|
|
* in the relevant component. Each group object contains the name of the group and an array of the
|
|
* field objects that belong to that group.
|
|
*
|
|
* It first filters the resource attributes to only include those that are not hidden
|
|
* in the given component. Then it groups the attributes by the group name
|
|
* (or "noGroupFound" if there is no group name). If the component is 'Show', it also
|
|
* checks if the resource object has data to display in each group. If not,
|
|
* the group is not included.
|
|
*
|
|
* @param {String} component - The component name (e.g. 'Form' or 'Show').
|
|
* @param {Object} resource - The resource object (optional).
|
|
* @return {Array} The array of group objects.
|
|
*/
|
|
const getFieldGroupings = (component, resource) => {
|
|
const attributesToConsider = resourceConfig.resourceAttrs.reduce(
|
|
(acc, ra) => {
|
|
if (ra.type === "relationshipWidget") {
|
|
ra.relationshipFields.forEach(relationshipField => {
|
|
relationshipField.relationshipName = ra.name;
|
|
});
|
|
}
|
|
const shouldFieldBeHidden =
|
|
ra.hideIn && typeof ra.hideIn === "function"
|
|
? ra.hideIn()
|
|
: ra.hideIn;
|
|
if (
|
|
shouldFieldBeHidden &&
|
|
!shouldFieldBeHidden.includes(component)
|
|
) {
|
|
return [...acc, ra];
|
|
}
|
|
if (
|
|
shouldFieldBeHidden &&
|
|
shouldFieldBeHidden.includes(component)
|
|
) {
|
|
return acc;
|
|
}
|
|
return [...acc, ra];
|
|
},
|
|
[]
|
|
);
|
|
if (resourceConfig.extendedAttributesResourceType) {
|
|
attributesToConsider.push({
|
|
name: "additional_fields",
|
|
type: "additional_fields",
|
|
extended_attributes_resource_type:
|
|
resourceConfig.extendedAttributesResourceType,
|
|
...(resourceConfig.extendedAttributesFieldGroup && {
|
|
group: resourceConfig.extendedAttributesFieldGroup,
|
|
}),
|
|
});
|
|
}
|
|
const groupings = attributesToConsider.reduce((acc, attr) => {
|
|
if (
|
|
attr.hasOwnProperty("group") &&
|
|
attr.group !== null &&
|
|
!acc.includes(attr.group)
|
|
) {
|
|
return [...acc, attr.group];
|
|
}
|
|
if (!attr.hasOwnProperty("group")) {
|
|
attr.group = "noGroupFound";
|
|
if (!acc.includes("noGroupFound")) {
|
|
return [...acc, "noGroupFound"];
|
|
}
|
|
}
|
|
return acc;
|
|
}, []);
|
|
if (groupings.length === 0) {
|
|
return [
|
|
{
|
|
name: null,
|
|
fields: attributesToConsider,
|
|
},
|
|
];
|
|
}
|
|
// FIXME - if no group is defined in accordion mode then the section doesn't have the dropdown applied
|
|
return groupings.reduce((acc, group) => {
|
|
const groupFields = attributesToConsider.filter(
|
|
ra => ra.group === group
|
|
);
|
|
const groupInfo = {
|
|
name: group === "noGroupFound" ? null : group,
|
|
fields: groupFields,
|
|
hasDataToDisplay: false,
|
|
};
|
|
if (
|
|
component === "Show" &&
|
|
resourceConfig.showGroupsDisplayMode === "splitScreen" &&
|
|
resourceConfig.splitScreenGroupings.length > 0
|
|
) {
|
|
const splitScreenGrouping =
|
|
resourceConfig.splitScreenGroupings.find(
|
|
g => g.name === group
|
|
);
|
|
if (splitScreenGrouping) {
|
|
groupInfo.splitPane = splitScreenGrouping.pane;
|
|
} else {
|
|
// Default to first pane
|
|
groupInfo.splitPane = 1;
|
|
}
|
|
}
|
|
if (component === "Show" && resource) {
|
|
groupFields.forEach(field => {
|
|
const hasStandardData =
|
|
resource[field.name] != null &&
|
|
(field.type !== "relationshipWidget" ||
|
|
resource[field.name].length > 0);
|
|
|
|
let hasFormattedData = false;
|
|
if (field.format && typeof field.format === "function") {
|
|
const formatted = field.format(
|
|
resource[field.name],
|
|
resource
|
|
);
|
|
hasFormattedData =
|
|
formatted !== null &&
|
|
formatted !== undefined &&
|
|
formatted !== "";
|
|
}
|
|
|
|
if (hasStandardData || hasFormattedData) {
|
|
groupInfo.hasDataToDisplay = true;
|
|
}
|
|
});
|
|
if (!groupInfo.hasDataToDisplay) {
|
|
return [...acc];
|
|
}
|
|
}
|
|
return [...acc, groupInfo];
|
|
}, []);
|
|
};
|
|
|
|
/**
|
|
* Retrieves a resource by id and assigns it to the component data.
|
|
* If the resource component has an 'afterResourceFetch' method, it is called
|
|
* with the component data, the fetched resource and the caller as arguments.
|
|
* When the resource is retrieved, the 'initialized' flag is set to true.
|
|
* @param {String} resourceId - The id of the resource to retrieve.
|
|
* @param {Object} componentData - The component data to assign the resource to.
|
|
* @param {String} caller - The name of the caller that requested the resource
|
|
* (e.g. 'form', 'list', 'show').
|
|
*/
|
|
const getResource = async (resourceId, componentData, caller) => {
|
|
resourceConfig.apiClient.get(resourceId).then(
|
|
resource => {
|
|
//TODO: Rename this 'resource' to 'fetchedResource'. Needs to also be renamed in ResourceFormSave and ResourceShow
|
|
// This is to make it clear that this is the fetchedResource (data), not the resource component class
|
|
componentData.resource.value = resource;
|
|
breadcrumbMetadata.value = resource;
|
|
if (componentData.instancedResource.afterResourceFetch) {
|
|
componentData.instancedResource.afterResourceFetch(
|
|
componentData,
|
|
resource,
|
|
caller
|
|
);
|
|
}
|
|
componentData.initialized.value = true;
|
|
},
|
|
error => {}
|
|
);
|
|
};
|
|
|
|
/**
|
|
* Returns the plural form of the resource name.
|
|
*
|
|
* This method checks if the `resourceName` ends with 's'. If it does not,
|
|
* it appends 's' to create the plural form. Otherwise returns `resourceName`.
|
|
*
|
|
* @return {String} The plural form of the resource name.
|
|
*/
|
|
const resourceNamePlural = computed(() => {
|
|
if (!resourceConfig.resourceName.endsWith("s"))
|
|
return resourceConfig.resourceName + "s";
|
|
return resourceConfig.resourceName;
|
|
});
|
|
|
|
/*
|
|
**********************************************************************
|
|
* RESOURCE CREATION RELATED METHODS
|
|
**********************************************************************
|
|
*/
|
|
|
|
/**
|
|
* Updates the extended_attributes property of the provided resource
|
|
*
|
|
* @param {Array} additionalFieldValues - Array of objects with
|
|
* name and value properties.
|
|
* @param {Object} resource - The resource object whose
|
|
* extended_attributes property is updated.
|
|
*/
|
|
const additionalFieldsChanged = (additionalFieldValues, resource) => {
|
|
resource.extended_attributes = additionalFieldValues;
|
|
};
|
|
|
|
/**
|
|
* Generates a new resource object with default values.
|
|
*
|
|
* This method initializes the `resourceToBeGenerated` property by iterating
|
|
* over `resourceAttrs`, assigning default values based on attribute types.
|
|
* - If an attribute has a `defaultValue`, it is set accordingly.
|
|
* - For text, textarea, and select types, an empty string is assigned.
|
|
* - For boolean and checkbox types, a false value is assigned.
|
|
* - For additional fields or relationship widgets, an empty array is assigned
|
|
* to `extended_attributes` or the attribute name.
|
|
* - If none of the above apply, a null value is assigned.
|
|
* The `idAttr` of the resource is also initialized to null.
|
|
*
|
|
* @return {Object} The newly generated resource object with default values.
|
|
*/
|
|
const newResource = computed(() => {
|
|
resourceConfig.resourceToBeGenerated =
|
|
resourceConfig.resourceAttrs.reduce((acc, attr) => {
|
|
if (attr.hasOwnProperty("defaultValue")) {
|
|
acc[attr.name] = attr.defaultValue;
|
|
return acc;
|
|
}
|
|
if (["text", "textarea", "select"].includes(attr.type)) {
|
|
acc[attr.name] = "";
|
|
return acc;
|
|
}
|
|
if (["boolean", "checkbox"].includes(attr.type)) {
|
|
acc[attr.name] = false;
|
|
return acc;
|
|
}
|
|
if (attr.type === "relationshipWidget") {
|
|
acc[attr.name] = [];
|
|
return acc;
|
|
}
|
|
acc[attr.name] = null;
|
|
return acc;
|
|
}, {});
|
|
if (resourceConfig.extendedAttributesResourceType) {
|
|
resourceConfig.resourceToBeGenerated.extended_attributes = [];
|
|
}
|
|
resourceConfig.resourceToBeGenerated[resourceConfig.idAttr] = null;
|
|
return resourceConfig.resourceToBeGenerated;
|
|
});
|
|
|
|
/*
|
|
**********************************************************************
|
|
* RESOURCE UTILITY METHODS
|
|
**********************************************************************
|
|
*/
|
|
|
|
/**
|
|
* Determines if the resource has additional fields.
|
|
*
|
|
* @return {Boolean} true if the resource has additional fields, false otherwise.
|
|
*/
|
|
const hasAdditionalFields = computed(() => {
|
|
return !!resourceConfig.extendedAttributesResourceType;
|
|
});
|
|
|
|
const refreshTemplate = ref(0);
|
|
/**
|
|
* Toggle the refreshTemplate flag of the resource.
|
|
* This flag is used to force a reload of the template by Vue.
|
|
* It is typically used when the data of the resource has been updated.
|
|
*
|
|
* @return {void}
|
|
*/
|
|
const refreshTemplateState = () => {
|
|
refreshTemplate.value++;
|
|
};
|
|
|
|
/**
|
|
* Populates the resource attributes with authorised values based on their types.
|
|
*
|
|
* For each attribute:
|
|
* - If the attribute type is "select" and it has an authorised value category (avCat),
|
|
* it sets the options from the component's corresponding property.
|
|
* - If the attribute type is "relationship" and it has component properties,
|
|
* it assigns authorised values to any marked as type 'av'.
|
|
* - If the attribute has relationship fields, the function is recursively called
|
|
* to populate them as well.
|
|
*
|
|
* @param {Array} attrs - The array of attributes to be populated with authorised values.
|
|
*/
|
|
const populateAttributesWithAuthorisedValues = attrs => {
|
|
const { authorisedValues } = moduleStoreUtils;
|
|
if (!attrs) return;
|
|
attrs.forEach(attr => {
|
|
if (attr.type === "select" && typeof attr.avCat === "string") {
|
|
const avKey = attr.avCat;
|
|
const avArray = authorisedValues[avKey];
|
|
if ((!avArray || !avArray.length) && attr.fallbackType) {
|
|
attr.type = attr.fallbackType;
|
|
} else {
|
|
attr.options = avArray;
|
|
attr.requiredKey = "value";
|
|
attr.selectLabel = "description";
|
|
}
|
|
}
|
|
if (attr.relationshipFields?.length) {
|
|
populateAttributesWithAuthorisedValues(attr.relationshipFields);
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Initializes the component by populating resource attributes
|
|
* with their respective authorised values. This ensures that
|
|
* any select or relationship attributes have the correct options
|
|
* or authorised values assigned before the component is used.
|
|
*/
|
|
const created = () => {
|
|
if (resourceConfig.resourceAttrs) {
|
|
populateAttributesWithAuthorisedValues(
|
|
resourceConfig.resourceAttrs
|
|
);
|
|
}
|
|
};
|
|
|
|
created();
|
|
|
|
return {
|
|
...resourceConfig,
|
|
...moduleStoreUtils,
|
|
getFilterValues,
|
|
toolbarButtons,
|
|
defaultToolbarButtons,
|
|
additionalToolbarButtons,
|
|
goToResourceAdd,
|
|
getFieldGroupings,
|
|
created,
|
|
getResourceTableUrl,
|
|
getResourceShowURL,
|
|
goToResourceEdit,
|
|
getResource,
|
|
goToResourceShow,
|
|
goToResourceList,
|
|
appendToShow,
|
|
doResourceSelect,
|
|
doResourceDelete,
|
|
additionalFieldsChanged,
|
|
getTableFilterFormElementsLabel,
|
|
getTableFilterFormElements,
|
|
refreshTemplateState,
|
|
refreshTemplate,
|
|
resourceNamePlural,
|
|
hasAdditionalFields,
|
|
newResource,
|
|
setConfirmationDialog,
|
|
setMessage,
|
|
setError,
|
|
setWarning,
|
|
updateConfirmationDialogInputs,
|
|
build_url,
|
|
route,
|
|
router,
|
|
i18n,
|
|
};
|
|
}
|