Merge pull request #267 from okkez/fix-in-tail-parser

Fix preview functionality in in_tail wizard
This commit is contained in:
okkez 2018-10-03 13:08:00 +09:00 committed by GitHub
commit 71ff060590
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 493 additions and 152 deletions

View File

@ -26,12 +26,14 @@ import "startbootstrap-sb-admin/js/sb-admin";
import "startbootstrap-sb-admin/js/sb-admin-datatables";
import Vue from "vue/dist/vue.esm";
import Vuex from "vuex/dist/vuex.esm";
Vue.filter("to_json", function (value) {
return JSON.stringify(value);
});
window.Vue = Vue;
window.Vuex = Vuex;
import "../stylesheets/application.scss";

View File

@ -1,21 +1,20 @@
/* global _ */
"use strict";
import "lodash/lodash";
import store from "./store";
const ConfigField = {
template: "#vue-config-field",
props: [
"pluginType",
"option",
"initialExpression",
"initialTimeFormat",
"initialTextValue",
],
data: function() {
return {
expression: null,
timeFormat: null,
selectedValue: null,
checkboxValue: null,
textValue: null,
};
},
@ -27,13 +26,29 @@ const ConfigField = {
},
mounted: function() {
if (this.option.name === "expression") {
this.expression = this.initialExpression;
} else if (this.option.name === "time_format") {
this.timeFormat = this.initialTimeFormat;
if (this.option.type === "enum") {
this.selectedValue = this.option.default;
} else if (this.option.type === "bool") {
this.checkboxValue = this.option.default;
} else {
this.textValue = this.initialTextValue || this.option.default;
}
if (this.option.name === "message_format") {
store.commit("parserParams/setMessageFormat", this.selectedValue);
}
if (this.option.name === "rfc5424_time_format") {
store.commit("parserParams/setRfc5424TimeFormat", this.textValue);
}
if (this.option.name === "with_priority") {
store.commit("parserParams/setWithPriority", this.checkboxValue);
}
if (this.option.name === "expression") {
store.commit("parserParams/Expression", this.textValue);
}
if (this.option.name === "timeFormat") {
store.commit("parserParams/timeFormat", this.textValue);
}
},
updated: function() {
@ -45,27 +60,33 @@ const ConfigField = {
}
this.$nextTick(() => {
console.log("config-field updated");
$("[data-toggle=tooltip]").tooltip("dispose");
$("[data-toggle=tooltip]").tooltip("enable");
if ($("[data-toggle=tooltip]").tooltip) {
$("[data-toggle=tooltip]").tooltip("dispose");
$("[data-toggle=tooltip]").tooltip("enable");
}
});
},
watch: {
"expression": function(_newValue, _oldValue) {
this.$emit("change-parse-config", {
"expression": this.expression,
"timeFormat": this.timeFormat
});
},
"timeFormat": function(_newValue, _oldValue) {
this.$emit("change-parse-config", {
"expression": this.expression,
"timeFormat": this.timeFormat
});
}
},
methods: {
onChange: function(event) {
console.log("onChange", this.option.name, event.target.value);
if (this.option.name === "message_format") {
store.dispatch("parserParams/updateMessageFormat", event);
}
if (this.option.name === "rfc5424_time_format") {
store.dispatch("parserParams/updateRfc5424TimeFormat", event);
}
if (this.option.name === "with_priority") {
store.dispatch("parserParams/updateWithPriority", event);
}
if (this.option.name === "expression") {
store.dispatch("parserParams/updateExpression", event);
}
if (this.option.name === "timeFormat") {
store.dispatch("parserParams/updateTimeFormat", event);
}
this.$emit("change-parse-config", {});
},
inputId: function(pluginType, option) {
if (pluginType === "output") {
return `setting_${option.name}`;

View File

@ -3,14 +3,21 @@
import "lodash/lodash";
import "popper.js/dist/popper";
import "bootstrap/dist/js/bootstrap";
import OwnedPluginForm from "./owned_plugin_form";
import ParserPluginForm from "./parser_plugin_form";
import store from "./store";
$(document).ready(() => {
new Vue({
el: "#in-tail-parse",
store,
components: {
"owned-plugin-form": OwnedPluginForm
"parser-plugin-form": ParserPluginForm
},
props: [
"initialPluginName",
"pluginType",
"pluginLabel",
],
data: function() {
return {
"path": "",
@ -41,26 +48,31 @@ $(document).ready(() => {
},
mounted: function() {
this.parse = {};
this.$on("hook:updated", () => {
this.$nextTick(() => {
this.parseType = this.initialPluginName;
this.preview();
},
updated: function() {
this.$nextTick(() => {
if ($("[data-toggle=tooltip]").tooltip) {
$("[data-toggle=tooltip]").tooltip("dispose");
$("[data-toggle=tooltip]").tooltip("enable");
});
}
});
},
methods: {
onChangePluginName: function(name) {
console.log("#in-tail-parse onChangePluginName", name);
this.parseType = name;
this.updateHighlightedLines([]);
this.parse = {}; // clear parser plugin configuration
this.onChangeParseConfig();
},
onChangeParseConfig: function(data) {
console.log("#in-tail-parse onChangeParseConfig", data);
_.merge(this.parse, data);
console.log("#in-tail-parse onChangeParseConfig", store.getters["parserParams/toParams"]);
_.merge(this.parse, store.getters["parserParams/toParams"]);
this.preview();
},
onChangeFormats: function(data) {
console.log("in_tail_parse:onChangeFormats", data);
console.log("#in_tail_parse onChangeFormats", data);
_.merge(this.parse, data);
this.preview();
},
@ -124,9 +136,9 @@ $(document).ready(() => {
preview: function() {
console.log("preview!!!!");
if (this.previewAjax && this.previewAjax.state() === "pending") {
this.previewAjax.abort();
this.previewAjax.abort && this.previewAjax.abort();
}
const parseType = store.getters["parserParams/pluginName"];
this.previewAjax = $.ajax({
method: "POST",
url: `${relativeUrlRoot}/api/regexp_preview`,
@ -134,7 +146,7 @@ $(document).ready(() => {
"X-CSRF-Token": this.token
},
data: {
parse_type: _.isEmpty(this.parseType) ? "regexp" : this.parseType,
parse_type: _.isEmpty(parseType) ? "regexp" : parseType,
file: this.path,
plugin_config: this.parse
}

View File

@ -2,13 +2,11 @@
"use strict";
import "lodash/lodash";
import ParserMultilineForm from "./parser_multiline_form";
import ConfigField from "./config_field";
const OwnedPluginForm = {
template: "#vue-owned-plugin-form",
components: {
"parser-multiline-form": ParserMultilineForm,
"config-field": ConfigField
},
props: [
@ -26,10 +24,6 @@ const OwnedPluginForm = {
initialParams: {},
commonOptions: [],
advancedOptions: [],
expression: null,
timeFormat: null,
unwatchExpression: null,
unwatchTimeFormat: null
};
},
@ -71,12 +65,6 @@ const OwnedPluginForm = {
this.$emit("change-formats", data);
},
onChangeParseConfig: function(data) {
console.log("ownedPluginForm:onChangeParseConfig", data);
this.expression = data.expression;
this.timeFormat = data.timeFormat;
},
updateSection: function() {
$.ajax({
method: "GET",
@ -90,44 +78,7 @@ const OwnedPluginForm = {
}
}).then((data) => {
this.commonOptions = data.commonOptions;
let foundExpression = false;
let foundTimeFormat = false;
_.each(this.commonOptions, (option) => {
if (option.name === "expression") {
foundExpression = true;
this.expression = option.default;
this.unwatchExpression = this.$watch("expression", (newValue, oldValue) => {
console.log(newValue);
this.$emit("change-parse-config", {
"expression": this.expression,
"time_format": this.timeFormat
});
});
}
if (option.name === "time_format") {
foundTimeFormat = true;
this.timeFormat = option.default;
console.log(this.timeFormat);
this.unwatchTimeFormat = this.$watch("timeFormat", (newValue, oldValue) => {
console.log({"watch time_format": newValue});
this.$emit("change-parse-config", {
"expression": this.expression,
"time_format": this.timeFormat
});
});
}
if (!foundExpression && this.unwatchExpression) {
this.expression = null;
this.unwatchExpression();
this.unwatchExpression = null;
}
if (!foundTimeFormat && this.unwatchTimeFormat) {
this.timeFormat = null;
this.unwatchTimeFormat();
this.unwatchTimeFormat = null;
}
});
this.advancedOptions = data.advancedOptions;
});
},

View File

@ -0,0 +1,147 @@
/* global _ */
"use strict";
import "lodash/lodash";
import ParserMultilineForm from "./parser_multiline_form";
import ConfigField from "./config_field";
import store from "./store";
const ParserPluginForm = {
template: "#vue-parser-plugin-form",
components: {
"parser-multiline-form": ParserMultilineForm,
"config-field": ConfigField
},
props: [
"id",
"optionsJson",
"initialPluginName",
"initialParamsJson",
"pluginType",
"pluginLabel"
],
data: () => {
return {
pluginName: "",
options: [],
initialParams: {},
commonOptions: [],
advancedOptions: [],
expression: null,
timeFormat: null,
unwatchExpression: null,
unwatchTimeFormat: null
};
},
computed: {
token: function() {
return Rails.csrfToken();
}
},
mounted: function() {
this.options = JSON.parse(this.optionsJson);
this.initialParams = JSON.parse(this.initialParamsJson || "{}");
this.pluginName = this.initialPluginName;
store.commit("parserParams/setType", this.initialPluginName);
this.$once("data-loaded", () => {
this.updateSection();
});
this.$emit("data-loaded");
},
updated: function() {
this.$nextTick(() => {
if ($("[data-toggle=tooltip]").tooltip) {
$("[data-toggle=tooltip]").tooltip("dispose");
$("[data-toggle=tooltip]").tooltip("enable");
}
});
},
methods: {
onChange: function(event) {
store.dispatch("parserParams/updateType", event);
this.$emit("change-plugin-name", event.target.value);
this.updateSection();
},
onChangeFormats: function(data) {
console.log("parserPluginForm:onChangeFormats", data);
this.$emit("change-formats", data);
},
onChangeParseConfig: function(data) {
console.log("parserPluginForm:onChangeParseConfig");
this.$emit("change-parse-config", {});
},
updateSection: function() {
$.ajax({
method: "GET",
url: `${relativeUrlRoot}/api/config_definitions`,
headers: {
"X-CSRF-Token": this.token
},
data: {
type: this.pluginType,
name: this.pluginName
}
}).then((data) => {
this.commonOptions = data.commonOptions;
this.advancedOptions = data.advancedOptions;
let foundExpression = false;
let foundTimeFormat = false;
_.each(this.commonOptions, (option) => {
if (option.name === "expression") {
foundExpression = true;
this.expression = option.default;
this.unwatchExpression = this.$watch("expression", (newValue, oldValue) => {
console.log(newValue);
this.$emit("change-parse-config", {
"expression": this.expression,
"time_format": this.timeFormat
});
});
}
if (option.name === "time_format") {
foundTimeFormat = true;
this.timeFormat = option.default;
console.log(this.timeFormat);
this.unwatchTimeFormat = this.$watch("timeFormat", (newValue, oldValue) => {
console.log({"watch time_format": newValue});
this.$emit("change-parse-config", {
"expression": this.expression,
"time_format": this.timeFormat
});
});
}
if (!foundExpression && this.unwatchExpression) {
this.expression = null;
this.unwatchExpression();
this.unwatchExpression = null;
}
if (!foundTimeFormat && this.unwatchTimeFormat) {
this.timeFormat = null;
this.unwatchTimeFormat();
this.unwatchTimeFormat = null;
}
});
});
},
selectId: function(pluginType) {
return `setting_${pluginType}_type`;
},
selectClass: function(pluginType) {
return `${pluginType} form-control`;
},
selectName: function(pluginType) {
return `setting[${pluginType}_type]`;
}
}
};
export { ParserPluginForm as default };

View File

@ -3,12 +3,14 @@ import "lodash/lodash";
import "popper.js/dist/popper";
import "bootstrap/dist/js/bootstrap";
import OwnedPluginForm from "./owned_plugin_form";
import ParserPluginForm from "./parser_plugin_form";
window.addEventListener("load", () => {
new Vue({
el: "#plugin-setting",
components: {
"owned-plugin-form": OwnedPluginForm
"owned-plugin-form": OwnedPluginForm,
"parser-plugin-form": ParserPluginForm
},
data: () => {
return {};

View File

@ -0,0 +1,20 @@
import Vue from "vue/dist/vue.esm";
import Vuex from "vuex/dist/vuex.esm";
import { createNamespaceHelpers } from "vuex/dist/vuex.esm";
import createLogger from "vuex/dist/logger";
Vue.use(Vuex);
const debug = process.env.NODE_ENV !== 'production';
import parserParams from "./modules/parser_params";
const store = new Vuex.Store({
modules: {
parserParams,
},
strict: debug,
plugins: debug ? [createLogger()] : []
});
export { store as default };

View File

@ -0,0 +1,83 @@
"user strict";
const state = {
type: null,
expression: null,
timeFormat: null,
messageFormat: null,
rfc5424TimeFormat: null,
withPriority: null,
};
const getters = {
toParams: (state) => {
return {
expression: state.expression,
time_format: state.timeFormat,
message_format: state.messageFormat,
rfc5424_time_format: state.rfc5424TimeFormat,
with_priority: state.withPriority
};
},
pluginName: (state) => {
return state.type;
}
};
const actions = {
updateType({ commit, state }, event) {
commit("setType", event.target.value);
commit("clearParams");
},
updateExpression({ commit, state }, event) {
commit("setExpression", event.target.value);
},
updateTimeFormat({ commit, state }, event) {
commit("setTimeFormat", event.target.value);
},
updateMessageFormat({ commit, state }, event) {
commit("setMessageFormat", event.target.value);
},
updateRfc5424TimeFormat({ commit, state }, event) {
commit("setRfc5424TimeFormat", event.target.value);
},
updateWithPriority({ commit, state }, event) {
commit("setWithPriority", event.target.checked);
}
};
const mutations = {
setType(state, value) {
state.type = value;
},
setExpression(state, value) {
state.expression = value;
},
setTimeFormat(state, value) {
state.timeFormat = value;
},
setMessageFormat(state, value) {
state.messageFormat = value;
},
setRfc5424TimeFormat(state, value) {
state.rfc5424TimeFormat = value;
},
setWithPriority(state, value) {
state.withPriority = value;
},
clearParams(state) {
state.expression = null;
state.timeFormat = null;
state.messageFormat = null;
state.rfc5424TimeFormat = null;
state.withPriority = null;
}
};
export default {
namespaced: true,
state,
getters,
actions,
mutations
};

View File

@ -0,0 +1,22 @@
class Fluentd
module Setting
module FormatterAdvancedOptions
extend ActiveSupport::Concern
def advanced_options
[
:time_type,
:time_format,
:timezone,
:utc,
]
end
def hidden_options
[
:localtime
]
end
end
end
end

View File

@ -0,0 +1,27 @@
class Fluentd
module Setting
module ParserAdvancedOptions
extend ActiveSupport::Concern
def advanced_options
[
:types,
:null_value_pattern,
:null_empty_string,
:estimate_current_event,
:time_key,
:time_type,
:time_format,
:keep_time_key,
:utc,
]
end
def hidden_options
[
:localtime
]
end
end
end
end

View File

@ -18,7 +18,6 @@ class Fluentd
include Fluentd::Setting::PluginConfig
include Fluentd::Setting::SectionParser
include Fluentd::Setting::PluginParameter
include Fluentd::Setting::Label
included do
cattr_accessor :plugin_type, :plugin_name, :config_definition
@ -33,6 +32,18 @@ class Fluentd
include Fluentd::Setting::Pattern
end
if ["input", "filter", "output"].include?(type)
include Fluentd::Setting::Label
end
if ["parser"].include?(type)
include Fluentd::Setting::ParserAdvancedOptions
end
if ["formatter"].include?(type)
include Fluentd::Setting::FormatterAdvancedOptions
end
self.load_plugin_config do |_name, params|
params.each do |param_name, definition|
if definition[:section]

View File

@ -18,6 +18,10 @@ class Fluentd
:dir_permission
]
end
def advanced_options
[]
end
end
end
end

View File

@ -12,6 +12,10 @@ class Fluentd
def common_options
[]
end
def advanced_options
[]
end
end
end
end

View File

@ -21,7 +21,7 @@ class Fluentd
end
def advanced_options
[
super + [
:delimiter_pattern
]
end

View File

@ -16,9 +16,9 @@ class Fluentd
end
def hidden_options
[
super + [
:ignorecase,
:multiline
:multiline,
]
end
end

View File

@ -12,16 +12,10 @@ class Fluentd
end
def common_options
[
:time_format,
:with_priority,
]
end
def advanced_options
[
:message_format,
:rfc5424_time_format
:rfc5424_time_format,
:with_priority,
]
end
end

View File

@ -1,5 +1,6 @@
= render "shared/setting_errors"
= render "shared/vue/owned_plugin_form"
= render "shared/vue/parser_plugin_form"
= javascript_pack_tag("plugin_setting")
@ -26,12 +27,12 @@
"v-bind:plugin-label" => "'Storage'"}
- if setting.have_parse_section?
%owned-plugin-form{"v-bind:id" => "'parse-section'",
"v-bind:options-json" => "'#{Fluent::Plugin::PARSER_REGISTRY.map.keys.to_json}'",
"v-bind:initial-plugin-name" => "'#{setting.parse_type}'",
"v-bind:initial-params-json" => "'#{setting.class.initial_params[:parse]["0"].to_json}'",
"v-bind:plugin-type" => "'parse'",
"v-bind:plugin-label" => "'Parse'"}
%parser-plugin-form{"v-bind:id" => "'parse-section'",
"v-bind:options-json" => "'#{Fluent::Plugin::PARSER_REGISTRY.map.keys.to_json}'",
"v-bind:initial-plugin-name" => "'#{setting.parse_type}'",
"v-bind:initial-params-json" => "'#{setting.class.initial_params[:parse]["0"].to_json}'",
"v-bind:plugin-type" => "'parse'",
"v-bind:plugin-label" => "'Parse'"}
- if setting.have_format_section?
%owned-plugin-form{"v-bind:id" => "'format-section'",

View File

@ -8,6 +8,8 @@
{{ option.name | humanize }}
%select{"v-bind:id" => "inputId(pluginType, option)",
"v-bind:name" => "inputName(pluginType, option)",
"v-model.lazy" => "selectedValue",
"v-on:change" => "onChange",
"class" => "form-control"}
%option{"v-for" => "item in option.list",
"v-bind:value" => "item",
@ -17,6 +19,8 @@
%input{"v-bind:id" => "inputId(pluginType, option)",
"v-bind:name" => "inputName(pluginType, option)",
"v-bind:checked" => "checked(option.default)",
"v-model.lazy" => "checkboxValue",
"v-on:change" => "onChange",
"type" => "checkbox"}
%label{"v-bind:for" => "inputId(pluginType, option)",
"data-toggle" => "tooltip",
@ -29,21 +33,9 @@
"data-placement" => "right",
"v-bind:title" => "option.desc"}
{{ option.name | humanize }}
%template{"v-if" => 'option.name === "expression"'}
%input{"v-bind:id" => "inputId(pluginType, option)",
"v-bind:name" => "inputName(pluginType, option)",
"v-model.lazy" => "expression",
"type" => "text",
"class" => "form-control"}
%template{"v-else-if" => 'option.name === "time_format"'}
%input{"v-bind:id" => "inputId(pluginType, option)",
"v-bind:name" => "inputName(pluginType, option)",
"v-model.lazy" => "timeFormat",
"type" => "text",
"class" => "form-control"}
%template(v-else)
%input{"v-bind:id" => "inputId(pluginType, option)",
"v-bind:name" => "inputName(pluginType, option)",
"v-model.lazy" => "textValue",
"type" => "text",
"class" => "form-control"}
%input{"v-bind:id" => "inputId(pluginType, option)",
"v-bind:name" => "inputName(pluginType, option)",
"v-model.lazy" => "textValue",
"v-on:change" => "onChange",
"type" => "text",
"class" => "form-control"}

View File

@ -1,16 +1,16 @@
- add_javascript_pack_tag("in_tail_parse")
= render "shared/vue/owned_plugin_form"
= render "shared/vue/parser_plugin_form"
#in-tail-parse{"path" => setting.path}
%owned-plugin-form{"v-bind:id" => "'parse-section'",
"v-bind:options-json" => "'#{Fluent::Plugin::PARSER_REGISTRY.map.keys.to_json}'",
"v-bind:initial-plugin-name" => "'#{setting.parse_type || setting.guess_parse_type}'",
"v-bind:plugin-type" => "'parse'",
"v-bind:plugin-label" => "'Parse'",
"v-on:change-parse-config" => "onChangeParseConfig",
"v-on:change-plugin-name" => "onChangePluginName",
"v-on:change-formats" => "onChangeFormats"}
%parser-plugin-form{"v-bind:id" => "'parse-section'",
"v-bind:options-json" => "'#{Fluent::Plugin::PARSER_REGISTRY.map.keys.to_json}'",
"v-bind:initial-plugin-name" => "'#{setting.parse_type || setting.guess_parse_type}'",
"v-bind:plugin-type" => "'parse'",
"v-bind:plugin-label" => "'Parse'",
"v-on:change-parse-config" => "onChangeParseConfig",
"v-on:change-plugin-name" => "onChangePluginName",
"v-on:change-formats" => "onChangeFormats"}
.card.mb-3
%pre{"class" => "card-body", "v-html" => "highlightedLines"}

View File

@ -1,4 +1,3 @@
= render "shared/vue/parser_multiline_form"
= render "shared/vue/config_field"
%script{type: "text/x-template", id: "vue-owned-plugin-form"}
@ -15,14 +14,18 @@
"v-bind:value" => "option",
"v-bind:selected" => "pluginName===option"}
{{ option }}
%parser-multiline-form{"v-if" => 'pluginName==="multiline"',
"v-bind:plugin-type" => "pluginType",
"v-bind:common-options" => "commonOptions",
"v-on:change-formats" => "onChangeFormats"}
%template(v-else){"v-for" => "option in commonOptions"}
%config-field{"v-bind:plugin-type" => "pluginType",
"v-bind:option" => "option",
"v-bind:initial-expression" => "expression",
"v-bind:initial-time-format" => "timeFormat",
"v-bind:initial-text-value" => "initialParams[option.name]",
"v-on:change-parse-config" => "onChangeParseConfig"}
%config-field{"v-for" => "option in commonOptions",
"v-bind:key" => "option.name",
"v-bind:plugin-type" => "pluginType",
"v-bind:option" => "option"}
%template{"v-if" => '!_.isEmpty(advancedOptions)'}
.card.card-body.bg-light
%h4{"data-toggle" => "collapse", "href" => "#owned-plugin-advanced-setting"}
= icon('fa-caret-down')
= t('terms.advanced_setting')
#owned-plugin-advanced-setting.collapse
%config-field{"v-for" => "option in advancedOptions",
"v-bind:key" => "option.name",
"v-bind:plugin-type" => "pluginType",
"v-bind:option" => "option"}

View File

@ -0,0 +1,38 @@
= render "shared/vue/parser_multiline_form"
= render "shared/vue/config_field"
%script{type: "text/x-template", id: "vue-parser-plugin-form"}
.form-group.card.bg-light.mb-3{"v-bind:id" => "id"}
.card-body
%label{"v-bind:for" => "selectId(pluginType)"}
{{ pluginLabel }}
%select{"v-bind:id" => "selectId(pluginType)",
"v-bind:class" => "selectClass(pluginType)",
"v-bind:name" => "selectName(pluginType)",
"v-model" => "pluginName",
"v-on:change" => "onChange"}
%option{"v-for" => "option in options",
"v-bind:value" => "option",
"v-bind:selected" => "pluginName===option"}
{{ option }}
%parser-multiline-form{"v-if" => 'pluginName==="multiline"',
"v-bind:plugin-type" => "pluginType",
"v-bind:common-options" => "commonOptions",
"v-on:change-formats" => "onChangeFormats"}
%template(v-else)
%template{"v-for" => "option in commonOptions"}
%config-field{"v-bind:key" => "option.name",
"v-bind:plugin-type" => "pluginType",
"v-bind:option" => "option",
"v-bind:initial-text-value" => "initialParams[option.name]",
"v-on:change-parse-config" => "onChangeParseConfig"}
%template{"v-if" => '!_.isEmpty(advancedOptions)'}
.card.card-body.bg-light
%h4{"data-toggle" => "collapse", "href" => "#owned-plugin-advanced-setting"}
= icon('fa-caret-down')
= t('terms.advanced_setting')
#owned-plugin-advanced-setting.collapse
%config-field{"v-for" => "option in advancedOptions",
"v-bind:key" => "option.name",
"v-bind:plugin-type" => "pluginType",
"v-bind:option" => "option"}

View File

@ -47,12 +47,13 @@ module RegexpPreview
next unless record
last_pos = 0
record.each do |key, value|
start = chunk.index(value, last_pos)
finish = start + value.bytesize
v = value.to_s
start = chunk.index(v, last_pos)
finish = start + v.bytesize
last_pos = finish
parsed[:matches] << {
key: key,
matched: value,
matched: v,
pos: [start, finish]
}
end

View File

@ -36,12 +36,13 @@ module RegexpPreview
next unless record
last_pos = 0
record.each do |key, value|
start = line.index(value, last_pos)
finish = start + value.bytesize
v = value.to_s
start = line.index(v, last_pos)
finish = start + v.bytesize
last_pos = finish
parsed[:matches] << {
key: key,
matched: value,
matched: v,
pos: [start, finish]
}
end

View File

@ -15,7 +15,8 @@
"startbootstrap-sb-admin": "^4.0.0",
"vue": "^2.5.16",
"vue-loader": "14.2.2",
"vue-template-compiler": "^2.5.16"
"vue-template-compiler": "^2.5.16",
"vuex": "^3.0.1"
},
"devDependencies": {
"eslint": "^5.1.0",

View File

@ -6414,6 +6414,10 @@ vue@^2.5.16:
version "2.5.16"
resolved "https://registry.yarnpkg.com/vue/-/vue-2.5.16.tgz#07edb75e8412aaeed871ebafa99f4672584a0085"
vuex@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.0.1.tgz#e761352ebe0af537d4bb755a9b9dc4be3df7efd2"
watchpack@^1.4.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00"