Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pkp/pkp-lib#9494 #9496

Merged
merged 1 commit into from
Nov 14, 2023
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
39 changes: 39 additions & 0 deletions js/classes/VueRegistry.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ export default {
*/
_instances: {},

/**
* Registry of all global components
*/
_globalComponents: {},

/**
* Initialize a Vue controller
*
Expand Down Expand Up @@ -62,4 +67,38 @@ export default {
}
});
},

/**
* Keeps track of all globally registered vue components
*
* This is important especially for plugins with custom vue components
* All global components gets automatically registered for each vue instance thats created
* It has same signature as vueInstance.component()
* @param string componentName
* @param object component
*/
registerComponent(componentName, component) {
this._globalComponents[componentName] = component;
},

/**
* Allow possibility to allow retrive component object
*
* Should be needed very rarely. This is important for some plugins which currently extends existing component, like FieldPubIdUrn
* @param string Able to retrieve component object
*/
getComponent(componentName) {
return this._globalComponents[componentName];
},

/**
* Provides all globaly registered components
*
* Main reason is to be able get all components to be registered in lib/pkp/load.js
* for every vue instance which is created
* @returns object Object of all components, where key is component name and value component object
*/
getAllComponents() {
return this._globalComponents;
},
};
201 changes: 112 additions & 89 deletions js/load.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@

// Vue lib and custom mixins
import {createApp} from 'vue';
import {createPinia} from 'pinia'
import * as vue from 'vue';
Comment on lines 12 to +13
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can join both lines into a single import, but not important :)


import {createPinia} from 'pinia';
import GlobalMixins from '@/mixins/global.js';
import VueAnnouncer from '@vue-a11y/announcer';
import FloatingVue from 'floating-vue';
Expand Down Expand Up @@ -99,18 +100,116 @@ import ListPanel from '@/components/ListPanel/ListPanel.vue';
import VueRegistry from './classes/VueRegistry.js';
import i18nPlugin from '@/piniaPlugins/i18n.plugin.js';

// Register global components
VueRegistry.registerComponent('Badge', Badge);
Copy link
Contributor

@jonasraoni jonasraoni Nov 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If all components are properly named, I think we could extract the name dynamically from them (e.g. Vue.component(component.name, component);), and move these registrations into a loop.

I don't know what's the reasoning for registering Spinner and PkpSpinner (I imagine that it started with Button, then conflicted with real HTML elements, and was moved to PkpButton). Perhaps it's a good time to standardize the naming, given that probably nobody extended the Vue components 🤔

Copy link
Contributor Author

@jardakotesovec jardakotesovec Nov 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Naming was bit mixed, likely due some name conflicts with native elements. So when I was exposing bigger part of ui-library to be available for plugins for 3.4, I kept the existing ones to avoid any surprises as 3.4 was already released and basically just exposed everything with pkp prefix. But its good point for 3.5 that might be good opportunity to get rid of the ones without prefix. Will consider it in separate PR.

Getting name from the component itself is also good suggestion, will keep it in mind when I review this logic. Not sure how the naming works for the components using composition api.

I also need to consider at some point whether to possibly expose all components globally, so they can be easily replaced from plugin via registry, that could be quite powerful way if someone needs some more significant customisation.

VueRegistry.registerComponent('PkpBadge', Badge);
VueRegistry.registerComponent('Dropdown', Dropdown);
VueRegistry.registerComponent('PkpDropdown', Dropdown);
VueRegistry.registerComponent('Icon', Icon);
VueRegistry.registerComponent('PkpIcon', Icon);
VueRegistry.registerComponent('Notification', Notification);
VueRegistry.registerComponent('PkpNotification', Notification);
VueRegistry.registerComponent('Panel', Panel);
VueRegistry.registerComponent('PkpPanel', Panel);
VueRegistry.registerComponent('PanelSection', PanelSection);
VueRegistry.registerComponent('PkpPanelSection', PanelSection);
VueRegistry.registerComponent('PkpButton', PkpButton);
VueRegistry.registerComponent('PkpHeader', PkpHeader);
VueRegistry.registerComponent('Spinner', Spinner);
VueRegistry.registerComponent('PkpSpinner', Spinner);
VueRegistry.registerComponent('Step', Step);
VueRegistry.registerComponent('PkpStep', Step);
VueRegistry.registerComponent('Steps', Steps);
VueRegistry.registerComponent('PkpSteps', Steps);
VueRegistry.registerComponent('Tab', Tab);
VueRegistry.registerComponent('PkpTab', Tab);
VueRegistry.registerComponent('Tabs', Tabs);
VueRegistry.registerComponent('PkpTabs', Tabs);

// Register other components
VueRegistry.registerComponent('PkpActionPanel', ActionPanel);
VueRegistry.registerComponent('PkpButtonRow', ButtonRow);
VueRegistry.registerComponent('PkpDoughnutChart', DoughnutChart);
VueRegistry.registerComponent('PkpLineChart', LineChart);
VueRegistry.registerComponent('PkpComposer', Composer);
VueRegistry.registerComponent('PkpDateRange', DateRange);
VueRegistry.registerComponent('PkpFile', File);
VueRegistry.registerComponent('PkpFileAttacher', FileAttacher);
VueRegistry.registerComponent('PkpFileUploader', FileUploader);
VueRegistry.registerComponent('PkpFileUploadProgress', FileUploadProgress);
VueRegistry.registerComponent('PkpFilter', PkpFilter);
VueRegistry.registerComponent('PkpFilterAutosuggest', FilterAutosuggest);
VueRegistry.registerComponent('PkpFilterSlider', FilterSlider);
VueRegistry.registerComponent(
'PkpFilterSliderMultirange',
FilterSliderMultirange,
);
VueRegistry.registerComponent('PkpList', List);
VueRegistry.registerComponent('PkpListItem', ListItem);
VueRegistry.registerComponent('PkpModal', Modal);
VueRegistry.registerComponent('PkpMultilingualProgress', MultilingualProgress);
VueRegistry.registerComponent('PkpOrderer', Orderer);
VueRegistry.registerComponent('PkpPagination', Pagination);
VueRegistry.registerComponent('PkpProgressBar', ProgressBar);
VueRegistry.registerComponent('PkpSearch', Search);
VueRegistry.registerComponent('PkpTable', Table);
VueRegistry.registerComponent('PkpTableCell', TableCell);
VueRegistry.registerComponent('PkpTooltip', Tooltip);

// Register Form components
VueRegistry.registerComponent('PkpForm', Form);
VueRegistry.registerComponent('PkpFieldArchivingPn', FieldArchivingPn);
VueRegistry.registerComponent(
'PkpFieldAutosuggestPreset',
FieldAutosuggestPreset,
);
VueRegistry.registerComponent('PkpFieldBase', FieldBase);
VueRegistry.registerComponent('PkpFieldBaseAutosuggest', FieldBaseAutosuggest);
VueRegistry.registerComponent('PkpFieldColor', FieldColor);
VueRegistry.registerComponent('PkpFieldControlledVocab', FieldControlledVocab);
VueRegistry.registerComponent('PkpFieldHtml', FieldHtml);
VueRegistry.registerComponent('PkpFieldMetadataSetting', FieldMetadataSetting);
VueRegistry.registerComponent('PkpFieldOptions', FieldOptions);
VueRegistry.registerComponent('PkpFieldPreparedContent', FieldPreparedContent);
VueRegistry.registerComponent('PkpFieldPubId', FieldPubId);
VueRegistry.registerComponent('PkpFieldRadioInput', FieldRadioInput);
VueRegistry.registerComponent('PkpFieldRichText', FieldRichText);
VueRegistry.registerComponent('PkpFieldRichTextarea', FieldRichTextarea);
VueRegistry.registerComponent('PkpFieldSelect', FieldSelect);
VueRegistry.registerComponent('PkpFieldSelectIssue', FieldSelectIssue);
VueRegistry.registerComponent('PkpFieldSelectIssues', FieldSelectIssues);
VueRegistry.registerComponent(
'PkpFieldSelectSubmissions',
FieldSelectSubmissions,
);
VueRegistry.registerComponent('PkpFieldSelectUsers', FieldSelectUsers);
VueRegistry.registerComponent(
'PkpFieldShowEnsuringLink',
FieldShowEnsuringLink,
);
VueRegistry.registerComponent('PkpFieldText', FieldText);
VueRegistry.registerComponent('PkpFieldTextarea', FieldTextarea);
VueRegistry.registerComponent('PkpFieldUpload', FieldUpload);
VueRegistry.registerComponent('PkpFieldUploadImage', FieldUploadImage);

// Required by the URN plugin, to be migrated at some point to pkp prefix
VueRegistry.registerComponent('field-text', FieldText);
VueRegistry.registerComponent('field-pub-id', FieldPubId);

// Register ListPanel
VueRegistry.registerComponent('PkpListPanel', ListPanel);

function pkpCreateVueApp(createAppArgs) {
// Initialize Vue
const vueApp = createApp(createAppArgs);
const pinia = createPinia(i18nPlugin);
pinia.use(i18nPlugin)
pinia.use(i18nPlugin);
vueApp.use(pinia);

// https://github.com/vuejs/pinia/discussions/1197
// to be able globally share stores
vueApp.config.globalProperties.$store = {};


// For compatibility with vue2 to preserve spaces between html tags
vueApp.config.compilerOptions.whitespace = 'preserve';
vueApp.use(VueScrollTo);
Expand All @@ -130,98 +229,22 @@ function pkpCreateVueApp(createAppArgs) {

vueApp.mixin(GlobalMixins);

// Register global components
vueApp.component('Badge', Badge);
vueApp.component('PkpBadge', Badge);
vueApp.component('Dropdown', Dropdown);
vueApp.component('PkpDropdown', Dropdown);
vueApp.component('Icon', Icon);
vueApp.component('PkpIcon', Icon);
vueApp.component('Notification', Notification);
vueApp.component('PkpNotification', Notification);
vueApp.component('Panel', Panel);
vueApp.component('PkpPanel', Panel);
vueApp.component('PanelSection', PanelSection);
vueApp.component('PkpPanelSection', PanelSection);
vueApp.component('PkpButton', PkpButton);
vueApp.component('PkpHeader', PkpHeader);
vueApp.component('Spinner', Spinner);
vueApp.component('PkpSpinner', Spinner);
vueApp.component('Step', Step);
vueApp.component('PkpStep', Step);
vueApp.component('Steps', Steps);
vueApp.component('PkpSteps', Steps);
vueApp.component('Tab', Tab);
vueApp.component('PkpTab', Tab);
vueApp.component('Tabs', Tabs);
vueApp.component('PkpTabs', Tabs);

// Register other components
vueApp.component('PkpActionPanel', ActionPanel);
vueApp.component('PkpButtonRow', ButtonRow);
vueApp.component('PkpDoughnutChart', DoughnutChart);
vueApp.component('PkpLineChart', LineChart);
vueApp.component('PkpComposer', Composer);
vueApp.component('PkpDateRange', DateRange);
vueApp.component('PkpFile', File);
vueApp.component('PkpFileAttacher', FileAttacher);
vueApp.component('PkpFileUploader', FileUploader);
vueApp.component('PkpFileUploadProgress', FileUploadProgress);
vueApp.component('PkpFilter', PkpFilter);
vueApp.component('PkpFilterAutosuggest', FilterAutosuggest);
vueApp.component('PkpFilterSlider', FilterSlider);
vueApp.component('PkpFilterSliderMultirange', FilterSliderMultirange);
vueApp.component('PkpList', List);
vueApp.component('PkpListItem', ListItem);
vueApp.component('PkpModal', Modal);
vueApp.component('PkpMultilingualProgress', MultilingualProgress);
vueApp.component('PkpOrderer', Orderer);
vueApp.component('PkpPagination', Pagination);
vueApp.component('PkpProgressBar', ProgressBar);
vueApp.component('PkpSearch', Search);
vueApp.component('PkpTable', Table);
vueApp.component('PkpTableCell', TableCell);
vueApp.component('PkpTooltip', Tooltip);

// Register Form components
vueApp.component('PkpForm', Form);
vueApp.component('PkpFieldArchivingPn', FieldArchivingPn);
vueApp.component('PkpFieldAutosuggestPreset', FieldAutosuggestPreset);
vueApp.component('PkpFieldBase', FieldBase);
vueApp.component('PkpFieldBaseAutosuggest', FieldBaseAutosuggest);
vueApp.component('PkpFieldColor', FieldColor);
vueApp.component('PkpFieldControlledVocab', FieldControlledVocab);
vueApp.component('PkpFieldHtml', FieldHtml);
vueApp.component('PkpFieldMetadataSetting', FieldMetadataSetting);
vueApp.component('PkpFieldOptions', FieldOptions);
vueApp.component('PkpFieldPreparedContent', FieldPreparedContent);
vueApp.component('PkpFieldPubId', FieldPubId);
vueApp.component('PkpFieldRadioInput', FieldRadioInput);
vueApp.component('PkpFieldRichText', FieldRichText);
vueApp.component('PkpFieldRichTextarea', FieldRichTextarea);
vueApp.component('PkpFieldSelect', FieldSelect);
vueApp.component('PkpFieldSelectIssue', FieldSelectIssue);
vueApp.component('PkpFieldSelectIssues', FieldSelectIssues);
vueApp.component('PkpFieldSelectSubmissions', FieldSelectSubmissions);
vueApp.component('PkpFieldSelectUsers', FieldSelectUsers);
vueApp.component('PkpFieldShowEnsuringLink', FieldShowEnsuringLink);
vueApp.component('PkpFieldText', FieldText);
vueApp.component('PkpFieldTextarea', FieldTextarea);
vueApp.component('PkpFieldUpload', FieldUpload);
vueApp.component('PkpFieldUploadImage', FieldUploadImage);

// Required by the URN plugin, to be migrated at some point to pkp prefix
vueApp.component('field-text', FieldText);
vueApp.component('field-pub-id', FieldPubId);

// Register ListPanel
vueApp.component('PkpListPanel', ListPanel);
// register all global components
const allGlobalComponents = VueRegistry.getAllComponents();
Object.keys(allGlobalComponents).forEach((componentName) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can replace by Object.entries(), then use ([name, component]) => ....

vueApp.component(componentName, allGlobalComponents[componentName]);
});

return vueApp;
}

export default {
Vue: pkpCreateVueApp({}),
// making vue functions available via pkp.modules.vue for plugins
// especially useful when using composition api
modules: {
vue,
},
pkpCreateVueApp,
createApp,
registry: VueRegistry,
Expand Down