Skip to content

Commit

Permalink
Add module JS file to handle Vue apps (#2584)
Browse files Browse the repository at this point in the history
* wip jsbundling-rails

* wip esbuild

* working sso mapping app

* clean

* fix

* gitignore

* fix

* eslint override
  • Loading branch information
SebouChu authored Jan 20, 2025
1 parent 77e135d commit a6dd536
Show file tree
Hide file tree
Showing 16 changed files with 299 additions and 47 deletions.
8 changes: 8 additions & 0 deletions .eslintrc.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
env:
browser: true
extends: "eslint:recommended"
overrides:
- files: ["app/javascript/**/*.js", "*.vue"]
env:
browser: true
es6: true
parserOptions:
sourceType: module

rules:
# key: 0 = allow, 1 = warn, 2 = error

Expand Down
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,8 @@ yarn-debug.log*
/db/scalingo-dump.tar.gz

# Ignore coverage report
coverage
coverage

# Ignore esbuild builds
/app/assets/builds/*
!/app/assets/builds/.keep
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ gem "image_processing"
gem "jbuilder"
gem "jquery-rails"
gem "jquery-ui-rails", git: "https://github.com/jquery-ui-rails/jquery-ui-rails.git", tag: "v7.0.0"
gem "jsbundling-rails", "~> 1.3"
gem "kamifusen"#, path: "../kamifusen"
gem "kaminari"
gem "leaflet-rails"
Expand Down
3 changes: 3 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,8 @@ GEM
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
jsbundling-rails (1.3.1)
railties (>= 6.0.0)
json (2.9.1)
json-schema (5.1.1)
addressable (~> 2.8)
Expand Down Expand Up @@ -742,6 +744,7 @@ DEPENDENCIES
jbuilder
jquery-rails
jquery-ui-rails!
jsbundling-rails (~> 1.3)
kamifusen
kaminari
leaflet-rails
Expand Down
2 changes: 2 additions & 0 deletions Procfile.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
web: bin/rails server
js: yarn build --watch
Empty file added app/assets/builds/.keep
Empty file.
1 change: 1 addition & 0 deletions app/assets/config/manifest.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//= link_tree ../examples
//= link_tree ../images
//= link_tree ../fonts
//= link_tree ../builds
//= link_directory ../stylesheets .css
//= link_directory ../javascripts .js
//= link vue.js
1 change: 1 addition & 0 deletions app/javascript/admin-module.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import "./apps"
40 changes: 40 additions & 0 deletions app/javascript/apps/SsoMappingApp.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<script>
import { VueDraggableNext } from "vue-draggable-next";
const appElt = document.querySelector('#sso-mapping-app');
export default {
components: {
draggable: VueDraggableNext,
},
data () {
return {
fields: JSON.parse(appElt.dataset.fields),
keys: JSON.parse(appElt.dataset.keys)
}
},
methods: {
addField: function () {
this.fields.push({sso_key: 'key', internal_key: 'email', roles: {}});
console.log(this.fields);
this.enableSelects();
},
enableSelects: function () {
// conditional.js messes with the new field added, so we have to force enable the select fields
var selectFields,
target,
i;
setTimeout(function() {
selectFields = document.getElementsByClassName("form-select");
for (i = 0; i < selectFields.length; i += 1) {
target = selectFields[i];
target.removeAttribute('disabled');
}
}, 100);
}
},
mounted() {
this.enableSelects();
}
};
</script>
6 changes: 6 additions & 0 deletions app/javascript/apps/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { createApp } from 'vue';
import SsoMappingApp from './SsoMappingApp.vue';

if (document.getElementById('sso-mapping-app')) {
createApp(SsoMappingApp).mount('#sso-mapping-app');
}
1 change: 1 addition & 0 deletions app/views/admin/layouts/application.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
<%= render "admin/application/components/realm" %>
<%= render "admin/application/components/footer" %>
<%= javascript_include_tag 'admin' %>
<%= javascript_include_tag 'admin-module', type: 'module' %>
<%= render 'bugsnag' %>
<%= render 'summernote_localization' %>
</body>
Expand Down
54 changes: 8 additions & 46 deletions app/views/server/universities/_sso_mapping.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ if kind == 'university'
else
mapping_keys = ['email', 'first_name', 'last_name', 'mobile_phone', 'language', 'picture_url']
end
%>

<%# Include vue.js before call Vue.createApp %>
<%= javascript_include_tag 'vue' %>
fieldsPropValue = object.sso_mapping.blank? ? [] : object.sso_mapping
keysPropValue = mapping_keys.map { |key| [key, User.human_attribute_name(key)] }.to_h
%>

<div id="app" v-cloak>
<div id="sso-mapping-app"
data-fields="<%= fieldsPropValue.to_json %>"
data-keys="<%= keysPropValue.to_json %>"
v-cloak>
<div class="spinner-border text-primary" role="status">
<span class="sr-only"><%= t('loading') %></span>
</div>
Expand Down Expand Up @@ -63,7 +66,7 @@ end
</div>
</draggable>

<a v-on:click="addField" class="btn btn-primary btn-sm">
<a @click="addField" class="btn btn-primary btn-sm">
<%= t('add_field') %>
</a>
</div>
Expand All @@ -73,44 +76,3 @@ end
</textarea>

</div>

<script nonce="<%= request.content_security_policy_nonce %>">
var app = Vue.createApp({
components: {
draggable: VueDraggableNext.VueDraggableNext,
},
data() {
return {
fields: <%= object.sso_mapping.blank? ? '[]' : object.sso_mapping.to_json.html_safe %>,
keys: <%= mapping_keys.map { |key| [key, User.human_attribute_name(key)] }.to_h.to_json.html_safe %>
}
},
methods: {
addField: function () {
this.fields.push({sso_key: 'key', internal_key: 'email', roles: {}});
this.enableSelects();
},
enableSelects: function () {
// conditional.js messes with the new field added, so we have to force enable the select fields
var selectFields,
i;
setTimeout(function() {
selectFields = document.getElementById("app").getElementsByClassName("form-select");
for (i = 0; i < selectFields.length; i += 1) {
target = selectFields[i];
target.removeAttribute('disabled');
}
}, 100);
}
},
mounted() {
this.enableSelects();
}
});

window.addEventListener('load', function(){
setTimeout(function() {
app.mount('#app');
}, 1000);
});
</script>
11 changes: 11 additions & 0 deletions bin/dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/usr/bin/env sh

if gem list --no-installed --exact --silent foreman; then
echo "Installing foreman..."
gem install foreman
fi

# Default to port 3000 if not specified
export PORT="${PORT:-3000}"

exec foreman start -f Procfile.dev --env /dev/null "$@"
31 changes: 31 additions & 0 deletions bin/esbuild
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/usr/bin/env node

import * as esbuild from 'esbuild'
import vuePlugin from 'esbuild-plugin-vue-next'

const options = {
entryPoints: ['app/javascript/admin-module.js'],
bundle: true,
sourcemap: true,
format: 'esm',
outdir: 'app/assets/builds',
publicPath: '/assets',
logLevel: 'info',
plugins: [vuePlugin()],
define: {
__VUE_OPTIONS_API__: 'true',
__VUE_PROD_DEVTOOLS__: 'false',
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__: 'false'
},
alias: {
'vue': 'vue/dist/vue.esm-bundler.js',
},
}
const watchMode = process.argv.includes('--watch')

if (watchMode) {
let ctx = await esbuild.context(options)
await ctx.watch()
} else {
await esbuild.build(options)
}
7 changes: 7 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,12 @@
"sortablejs": "^1.14.0",
"vue": "^3.2.31",
"vue-draggable-next": "^2.1.1"
},
"devDependencies": {
"esbuild": "^0.24.2",
"esbuild-plugin-vue-next": "^0.1.4"
},
"scripts": {
"build": "node bin/esbuild"
}
}
Loading

0 comments on commit a6dd536

Please sign in to comment.