summaryrefslogtreecommitdiff
path: root/doc/development/ee_features.md
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-07-20 12:26:25 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-07-20 12:26:25 +0000
commita09983ae35713f5a2bbb100981116d31ce99826e (patch)
tree2ee2af7bd104d57086db360a7e6d8c9d5d43667a /doc/development/ee_features.md
parent18c5ab32b738c0b6ecb4d0df3994000482f34bd8 (diff)
downloadgitlab-ce-a09983ae35713f5a2bbb100981116d31ce99826e.tar.gz
Add latest changes from gitlab-org/gitlab@13-2-stable-ee
Diffstat (limited to 'doc/development/ee_features.md')
-rw-r--r--doc/development/ee_features.md88
1 files changed, 70 insertions, 18 deletions
diff --git a/doc/development/ee_features.md b/doc/development/ee_features.md
index e22e96b6f06..ac544113cbd 100644
--- a/doc/development/ee_features.md
+++ b/doc/development/ee_features.md
@@ -512,12 +512,12 @@ do that, so we'll follow regular object-oriented practices that we define the
interface first here.
For example, suppose we have a few more optional parameters for EE. We can move the
-parameters out of the `Grape::API` class to a helper module, so we can inject it
+parameters out of the `Grape::API::Instance` class to a helper module, so we can inject it
before it would be used in the class.
```ruby
module API
- class Projects < Grape::API
+ class Projects < Grape::API::Instance
helpers Helpers::ProjectsHelpers
end
end
@@ -578,7 +578,7 @@ class definition to make it easy and clear:
```ruby
module API
- class JobArtifacts < Grape::API
+ class JobArtifacts < Grape::API::Instance
# EE::API::JobArtifacts would override the following helpers
helpers do
def authorize_download_artifacts!
@@ -622,7 +622,7 @@ route. Something like this:
```ruby
module API
- class MergeRequests < Grape::API
+ class MergeRequests < Grape::API::Instance
helpers do
# EE::API::MergeRequests would override the following helpers
def update_merge_request_ee(merge_request)
@@ -691,7 +691,7 @@ least argument. We would approach this as follows:
```ruby
# api/merge_requests/parameters.rb
module API
- class MergeRequests < Grape::API
+ class MergeRequests < Grape::API::Instance
module Parameters
def self.update_params_at_least_one_of
%i[
@@ -707,7 +707,7 @@ API::MergeRequests::Parameters.prepend_if_ee('EE::API::MergeRequests::Parameters
# api/merge_requests.rb
module API
- class MergeRequests < Grape::API
+ class MergeRequests < Grape::API::Instance
params do
at_least_one_of(*Parameters.update_params_at_least_one_of)
end
@@ -900,27 +900,79 @@ export default {
</template>
```
-#### For JS code that is EE only, like props, computed properties, methods, etc, we will keep the current approach
+#### For JS code that is EE only, like props, computed properties, methods, etc
-- Since we [can't async load a mixin](https://github.com/vuejs/vue-loader/issues/418#issuecomment-254032223) we will use the [`ee_else_ce`](../development/ee_features.md#javascript-code-in-assetsjavascripts) alias we already have for webpack.
- - This means all the EE specific props, computed properties, methods, etc that are EE only should be in a mixin in the `ee/` folder and we need to create a CE counterpart of the mixin
+- Please do not use mixins unless ABSOLUTELY NECESSARY. Please try to find an alternative pattern.
-##### Example
+##### Reccomended alternative approach (named/scoped slots)
-```javascript
-import mixin from 'ee_else_ce/path/mixin';
+- We can use slots and/or scoped slots to achieve the same thing as we did with mixins. If you only need an EE component there is no need to create the CE component.
+
+1. First, we have a CE component that can render a slot incase we need EE template and functionality to be decorated on top of the CE base.
+
+```vue
+// ./ce/my_component.vue
+
+<script>
+export default {
+ props: {
+ tooltipDefaultText: {
+ type: String,
+ },
+ },
+ computed: {
+ tooltipText() {
+ return this.tooltipDefaultText || "5 issues please";
+ }
+ },
+}
+</script>
+
+<template>
+ <span v-gl-tooltip :title="tooltipText" class="ce-text">Community Edition Only Text</span>
+ <slot name="ee-specific-component">
+</template>
+```
+
+1. Next, we render the EE component, and inside of the EE component we render the CE component and add additional content in the slot.
-{
- mixins: [mixin]
+```vue
+// ./ee/my_component.vue
+
+<script>
+export default {
+ computed: {
+ tooltipText() {
+ if (this.weight) {
+ return "5 issues with weight 10";
+ }
+ }
+ },
+ methods: {
+ submit() {
+ // do something.
+ }
+ },
}
+</script>
+
+<template>
+ <my-component :tooltipDefaultText="tooltipText">
+ <template #ee-specific-component>
+ <span class="some-ee-specific">EE Specific Value</span>
+ <button @click="submit">Click Me</button>
+ </template>
+ </my-component>
+</template>
```
-- Computed Properties/methods and getters only used in the child import still need a counterpart in CE
+1. Finally, wherever the component is needed we can require it like so
+
+`import MyComponent from 'ee_else_ce/path/my_component'.vue`
-- For store modules, we will need a CE counterpart too.
-- You can see an MR with an example [here](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/9762)
+- this way the correct component will be included for either the ce or ee implementation
-#### `template` tag
+**For EE components that need different results for the same computed values, we can pass in props to the CE wrapper as seen in the example.**
- **EE Child components**
- Since we are using the async loading to check which component to load, we'd still use the component's name, check [this example](#child-component-only-used-in-ee).