diff --git a/app/controllers/account_configs_controller.rb b/app/controllers/account_configs_controller.rb
index 66683e3f..cf128ef9 100644
--- a/app/controllers/account_configs_controller.rb
+++ b/app/controllers/account_configs_controller.rb
@@ -19,6 +19,7 @@ class AccountConfigsController < ApplicationController
AccountConfig::FORCE_SSO_AUTH_KEY,
AccountConfig::FLATTEN_RESULT_PDF_KEY,
AccountConfig::ENFORCE_SIGNING_ORDER_KEY,
+ AccountConfig::WITH_FILE_LINKS_KEY,
AccountConfig::WITH_SIGNATURE_ID,
AccountConfig::COMBINE_PDF_RESULT_KEY,
AccountConfig::REQUIRE_SIGNING_REASON_KEY,
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 7500acdb..cd8d228c 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -13,6 +13,8 @@ class ApplicationController < ActionController::Base
before_action :maybe_redirect_to_setup, unless: :signed_in?
before_action :authenticate_user!, unless: :devise_controller?
+ before_action :set_csp, if: -> { request.get? && !request.headers['HTTP_X_TURBO'] }
+
helper_method :button_title,
:current_account,
:form_link_host,
@@ -123,4 +125,21 @@ class ApplicationController < ActionController::Base
redirect_to request.url.gsub('.co/', '.com/'), allow_other_host: true, status: :moved_permanently
end
+
+ def set_csp
+ request.content_security_policy = current_content_security_policy.tap do |policy|
+ policy.default_src :self
+ policy.script_src :self
+ policy.style_src :self, :unsafe_inline
+ policy.img_src :self, :https, :http, :blob, :data
+ policy.font_src :self, :https, :http, :blob, :data
+ policy.manifest_src :self
+ policy.media_src :self
+ policy.frame_src :self
+ policy.worker_src :self, :blob
+ policy.connect_src :self
+
+ policy.directives['connect-src'] << 'ws:' if Rails.env.development?
+ end
+ end
end
diff --git a/app/javascript/application.js b/app/javascript/application.js
index 7b51186d..a9fb02d0 100644
--- a/app/javascript/application.js
+++ b/app/javascript/application.js
@@ -23,6 +23,7 @@ import SignatureForm from './elements/signature_form'
import SubmitForm from './elements/submit_form'
import PromptPassword from './elements/prompt_password'
import EmailsTextarea from './elements/emails_textarea'
+import ToggleSubmit from './elements/toggle_submit'
import ToggleOnSubmit from './elements/toggle_on_submit'
import CheckOnClick from './elements/check_on_click'
import PasswordInput from './elements/password_input'
@@ -34,11 +35,20 @@ import MaskedInput from './elements/masked_input'
import SetDateButton from './elements/set_date_button'
import IndeterminateCheckbox from './elements/indeterminate_checkbox'
import AppTour from './elements/app_tour'
+import AppTourStart from './elements/app_tour_start'
import DashboardDropzone from './elements/dashboard_dropzone'
import RequiredCheckboxGroup from './elements/required_checkbox_group'
import PageContainer from './elements/page_container'
import EmailEditor from './elements/email_editor'
import MountOnClick from './elements/mount_on_click'
+import RemoveOnEvent from './elements/remove_on_event'
+import ScrollTo from './elements/scroll_to'
+import SetValue from './elements/set_value'
+import ReviewForm from './elements/review_form'
+import ShowOnValue from './elements/show_on_value'
+import CustomValidation from './elements/custom_validation'
+import ToggleClasses from './elements/toggle_classes'
+import AutosizeField from './elements/autosize_field'
import * as TurboInstantClick from './lib/turbo_instant_click'
@@ -55,6 +65,9 @@ document.addEventListener('keyup', (e) => {
})
document.addEventListener('turbo:before-fetch-request', encodeMethodIntoRequestBody)
+document.addEventListener('turbo:before-fetch-request', (event) => {
+ event.detail.fetchOptions.headers['X-Turbo'] = 'true'
+})
document.addEventListener('turbo:submit-end', async (event) => {
const resp = event.detail?.formSubmission?.result?.fetchResponse?.response
@@ -97,6 +110,7 @@ safeRegisterElement('submit-form', SubmitForm)
safeRegisterElement('prompt-password', PromptPassword)
safeRegisterElement('emails-textarea', EmailsTextarea)
safeRegisterElement('toggle-cookies', ToggleCookies)
+safeRegisterElement('toggle-submit', ToggleSubmit)
safeRegisterElement('toggle-on-submit', ToggleOnSubmit)
safeRegisterElement('password-input', PasswordInput)
safeRegisterElement('search-input', SearchInput)
@@ -107,12 +121,21 @@ safeRegisterElement('masked-input', MaskedInput)
safeRegisterElement('set-date-button', SetDateButton)
safeRegisterElement('indeterminate-checkbox', IndeterminateCheckbox)
safeRegisterElement('app-tour', AppTour)
+safeRegisterElement('app-tour-start', AppTourStart)
safeRegisterElement('dashboard-dropzone', DashboardDropzone)
safeRegisterElement('check-on-click', CheckOnClick)
safeRegisterElement('required-checkbox-group', RequiredCheckboxGroup)
safeRegisterElement('page-container', PageContainer)
safeRegisterElement('email-editor', EmailEditor)
safeRegisterElement('mount-on-click', MountOnClick)
+safeRegisterElement('remove-on-event', RemoveOnEvent)
+safeRegisterElement('scroll-to', ScrollTo)
+safeRegisterElement('set-value', SetValue)
+safeRegisterElement('review-form', ReviewForm)
+safeRegisterElement('show-on-value', ShowOnValue)
+safeRegisterElement('custom-validation', CustomValidation)
+safeRegisterElement('toggle-classes', ToggleClasses)
+safeRegisterElement('autosize-field', AutosizeField)
safeRegisterElement('template-builder', class extends HTMLElement {
connectedCallback () {
diff --git a/app/javascript/application.scss b/app/javascript/application.scss
index 1ab92498..47eeb4f6 100644
--- a/app/javascript/application.scss
+++ b/app/javascript/application.scss
@@ -19,7 +19,7 @@ button .disabled {
display: none;
}
-button[disabled] .disabled {
+button[disabled] .disabled, button.btn-disabled .disabled {
display: initial;
}
@@ -27,7 +27,7 @@ button .enabled {
display: initial;
}
-button[disabled] .enabled {
+button[disabled] .enabled, button.btn-disabled .enabled {
display: none;
}
diff --git a/app/javascript/elements/app_tour_start.js b/app/javascript/elements/app_tour_start.js
new file mode 100644
index 00000000..1b06becb
--- /dev/null
+++ b/app/javascript/elements/app_tour_start.js
@@ -0,0 +1,7 @@
+export default class extends HTMLElement {
+ connectedCallback () {
+ this.querySelector('form').addEventListener('submit', () => {
+ window.app_tour.start()
+ })
+ }
+}
diff --git a/app/javascript/elements/autosize_field.js b/app/javascript/elements/autosize_field.js
new file mode 100644
index 00000000..b6f56763
--- /dev/null
+++ b/app/javascript/elements/autosize_field.js
@@ -0,0 +1,21 @@
+export default class extends HTMLElement {
+ connectedCallback () {
+ const originalFontValue = this.field.style.fontSize
+
+ if (this.field.scrollHeight > this.field.clientHeight) {
+ this.field.style.fontSize = `calc(${originalFontValue} / 1.5)`
+ this.field.style.lineHeight = `calc(${this.field.style.fontSize} * 1.3)`
+
+ if (this.field.scrollHeight > this.field.clientHeight) {
+ this.field.style.fontSize = `calc(${originalFontValue} / 2.0)`
+ this.field.style.lineHeight = `calc(${this.field.style.fontSize} * 1.3)`
+ }
+ }
+
+ this.field.classList.remove('hidden')
+ }
+
+ get field () {
+ return this.closest('field-value')
+ }
+}
diff --git a/app/javascript/elements/custom_validation.js b/app/javascript/elements/custom_validation.js
new file mode 100644
index 00000000..ac738679
--- /dev/null
+++ b/app/javascript/elements/custom_validation.js
@@ -0,0 +1,14 @@
+export default class extends HTMLElement {
+ connectedCallback () {
+ const input = this.querySelector('input')
+ const invalidMessage = this.dataset.invalidMessage || ''
+
+ input.addEventListener('invalid', () => {
+ input.setCustomValidity(input.value ? invalidMessage : '')
+ })
+
+ input.addEventListener('input', () => {
+ input.setCustomValidity('')
+ })
+ }
+}
diff --git a/app/javascript/elements/remove_on_event.js b/app/javascript/elements/remove_on_event.js
new file mode 100644
index 00000000..e912e4cd
--- /dev/null
+++ b/app/javascript/elements/remove_on_event.js
@@ -0,0 +1,15 @@
+export default class extends HTMLElement {
+ connectedCallback () {
+ const eventType = this.dataset.on || 'click'
+ const selector = document.getElementById(this.dataset.selectorId) || this
+ const eventElement = eventType === 'submit' ? this.querySelector('form') : this
+
+ eventElement.addEventListener(eventType, (event) => {
+ if (eventType === 'click') {
+ event.preventDefault()
+ }
+
+ selector.remove()
+ })
+ }
+}
diff --git a/app/javascript/elements/review_form.js b/app/javascript/elements/review_form.js
new file mode 100644
index 00000000..537fe602
--- /dev/null
+++ b/app/javascript/elements/review_form.js
@@ -0,0 +1,19 @@
+export default class extends HTMLElement {
+ connectedCallback () {
+ this.querySelectorAll('input[type="radio"]').forEach(radio => {
+ radio.addEventListener('change', (event) => {
+ const rating = parseInt(event.target.value)
+
+ if (rating === 10) {
+ window.review_comment.value = ''
+ window.review_comment.classList.add('hidden')
+ window.review_submit.classList.add('hidden')
+ event.target.form.submit()
+ } else {
+ window.review_comment.classList.remove('hidden')
+ window.review_submit.classList.remove('hidden')
+ }
+ })
+ })
+ }
+}
diff --git a/app/javascript/elements/scroll_to.js b/app/javascript/elements/scroll_to.js
new file mode 100644
index 00000000..ded724b5
--- /dev/null
+++ b/app/javascript/elements/scroll_to.js
@@ -0,0 +1,10 @@
+export default class extends HTMLElement {
+ connectedCallback () {
+ this.selector = document.getElementById(this.dataset.selectorId)
+
+ this.addEventListener('click', () => {
+ this.selector.scrollIntoView({ behavior: 'smooth', block: 'start' })
+ history.replaceState(null, null, `#${this.dataset.selectorId}`)
+ })
+ }
+}
diff --git a/app/javascript/elements/search_input.js b/app/javascript/elements/search_input.js
index 9b536ab3..585f7122 100644
--- a/app/javascript/elements/search_input.js
+++ b/app/javascript/elements/search_input.js
@@ -13,6 +13,14 @@ export default class extends HTMLElement {
this.input.classList.remove('w-60')
}
})
+
+ this.button.addEventListener('click', (event) => {
+ if (!this.input.value && document.activeElement !== this.input) {
+ event.preventDefault()
+
+ this.input.focus()
+ }
+ })
}
get input () {
@@ -22,4 +30,8 @@ export default class extends HTMLElement {
get title () {
return document.querySelector(this.dataset.title)
}
+
+ get button () {
+ return this.querySelector('button')
+ }
}
diff --git a/app/javascript/elements/set_value.js b/app/javascript/elements/set_value.js
new file mode 100644
index 00000000..49e05c9c
--- /dev/null
+++ b/app/javascript/elements/set_value.js
@@ -0,0 +1,11 @@
+export default class extends HTMLElement {
+ connectedCallback () {
+ const input = this.dataset.inputId ? document.getElementById(this.dataset.inputId) : this.querySelector('input')
+
+ this.firstElementChild.addEventListener(this.dataset.on || 'click', () => {
+ if (this.dataset.emptyOnly !== 'true' || !input.value) {
+ input.value = this.dataset.value
+ }
+ })
+ }
+}
diff --git a/app/javascript/elements/show_on_value.js b/app/javascript/elements/show_on_value.js
new file mode 100644
index 00000000..c969d823
--- /dev/null
+++ b/app/javascript/elements/show_on_value.js
@@ -0,0 +1,17 @@
+export default class extends HTMLElement {
+ connectedCallback () {
+ this.addEventListener('change', (event) => {
+ const targetValue = this.dataset.value
+ const selectorId = this.dataset.selectorId
+ const targetElement = document.getElementById(selectorId)
+
+ if (event.target.value === targetValue) {
+ targetElement.classList.remove('hidden')
+ } else {
+ targetElement.classList.add('hidden')
+ targetElement.value = ''
+ event.target.form.requestSubmit()
+ }
+ })
+ }
+}
diff --git a/app/javascript/elements/submit_form.js b/app/javascript/elements/submit_form.js
index 164a069e..e936c0bd 100644
--- a/app/javascript/elements/submit_form.js
+++ b/app/javascript/elements/submit_form.js
@@ -1,15 +1,27 @@
export default class extends HTMLElement {
connectedCallback () {
+ const form = this.querySelector('form') || (this.querySelector('input, button, select') || this.lastElementChild).form
+
if (this.dataset.interval) {
this.interval = setInterval(() => {
- this.querySelector('form').requestSubmit()
+ form.requestSubmit()
}, parseInt(this.dataset.interval))
} else if (this.dataset.on) {
- this.lastElementChild.addEventListener(this.dataset.on, () => {
- this.lastElementChild.form.requestSubmit()
+ this.lastElementChild.addEventListener(this.dataset.on, (event) => {
+ if (this.dataset.disable === 'true') {
+ form.querySelector('[type="submit"]')?.setAttribute('disabled', true)
+ }
+
+ if (this.dataset.submitIfValue === 'true') {
+ if (event.target.value) {
+ form.requestSubmit()
+ }
+ } else {
+ form.requestSubmit()
+ }
})
} else {
- this.querySelector('form').requestSubmit()
+ form.requestSubmit()
}
}
diff --git a/app/javascript/elements/toggle_classes.js b/app/javascript/elements/toggle_classes.js
new file mode 100644
index 00000000..ab96f293
--- /dev/null
+++ b/app/javascript/elements/toggle_classes.js
@@ -0,0 +1,11 @@
+export default class extends HTMLElement {
+ connectedCallback () {
+ const button = this.querySelector('a, button')
+
+ button.addEventListener('click', () => {
+ this.dataset.classes.split(' ').forEach((cls) => {
+ button.classList.toggle(cls)
+ })
+ })
+ }
+}
diff --git a/app/javascript/elements/toggle_visible.js b/app/javascript/elements/toggle_visible.js
index a796b9c6..7fa968f2 100644
--- a/app/javascript/elements/toggle_visible.js
+++ b/app/javascript/elements/toggle_visible.js
@@ -4,9 +4,15 @@ export default actionable(class extends HTMLElement {
trigger (event) {
const elementIds = JSON.parse(this.dataset.elementIds)
- elementIds.forEach((elementId) => {
- document.getElementById(elementId).classList.toggle('hidden', (event.target.dataset.toggleId || event.target.value) !== elementId)
- })
+ if (event.target.type === 'checkbox') {
+ elementIds.forEach((elementId) => {
+ document.getElementById(elementId)?.classList.toggle('hidden')
+ })
+ } else {
+ elementIds.forEach((elementId) => {
+ document.getElementById(elementId).classList.toggle('hidden', (event.target.dataset.toggleId || event.target.value) !== elementId)
+ })
+ }
if (this.dataset.focusId) {
document.getElementById(this.dataset.focusId)?.focus()
diff --git a/app/javascript/form.js b/app/javascript/form.js
index ac49174d..b8253f86 100644
--- a/app/javascript/form.js
+++ b/app/javascript/form.js
@@ -6,6 +6,7 @@ import ToggleSubmit from './elements/toggle_submit'
import FetchForm from './elements/fetch_form'
import ScrollButtons from './elements/scroll_buttons'
import PageContainer from './elements/page_container'
+import SubmitForm from './elements/submit_form'
const safeRegisterElement = (name, element, options = {}) => !window.customElements.get(name) && window.customElements.define(name, element, options)
@@ -14,6 +15,7 @@ safeRegisterElement('toggle-submit', ToggleSubmit)
safeRegisterElement('fetch-form', FetchForm)
safeRegisterElement('scroll-buttons', ScrollButtons)
safeRegisterElement('page-container', PageContainer)
+safeRegisterElement('submit-form', SubmitForm)
safeRegisterElement('submission-form', class extends HTMLElement {
connectedCallback () {
this.appElem = document.createElement('div')
diff --git a/app/javascript/form.scss b/app/javascript/form.scss
index f0d26baf..92fc6f6a 100644
--- a/app/javascript/form.scss
+++ b/app/javascript/form.scss
@@ -19,7 +19,7 @@ button .disabled {
display: none;
}
-button[disabled] .disabled {
+button[disabled] .disabled, button.btn-disabled .disabled {
display: initial;
}
@@ -27,7 +27,7 @@ button .enabled {
display: initial;
}
-button[disabled] .enabled {
+button[disabled] .enabled, button.btn-disabled .enabled {
display: none;
}
diff --git a/app/javascript/lib/turbo_instant_click.js b/app/javascript/lib/turbo_instant_click.js
index 01789e95..d72d4ce8 100644
--- a/app/javascript/lib/turbo_instant_click.js
+++ b/app/javascript/lib/turbo_instant_click.js
@@ -56,7 +56,7 @@ function mouseoverListener (event) {
const requestOptions = {
credentials: 'same-origin',
- headers: { Accept: 'text/html, application/xhtml+xml', 'VND.PREFETCH': 'true' },
+ headers: { Accept: 'text/html, application/xhtml+xml', 'VND.PREFETCH': 'true', 'X-Turbo': 'true' },
method: 'GET',
redirect: 'follow'
}
diff --git a/app/javascript/submission_form/area.vue b/app/javascript/submission_form/area.vue
index 784818b6..2a2fd20e 100644
--- a/app/javascript/submission_form/area.vue
+++ b/app/javascript/submission_form/area.vue
@@ -219,6 +219,48 @@
>
{{ formatNumber(modelValue, field.preferences?.format) }}
+
+
+
+
-
-
-
+
+
+
+
diff --git a/app/javascript/submission_form/form.vue b/app/javascript/submission_form/form.vue
index d58c04d8..7a825141 100644
--- a/app/javascript/submission_form/form.vue
+++ b/app/javascript/submission_form/form.vue
@@ -23,7 +23,7 @@
{
- acc[f.uuid] = (this.values[f.uuid] || f.default_value)
+ acc[f.uuid] = isEmpty(this.values[f.uuid]) ? f.default_value : this.values[f.uuid]
+
+ return acc
+ }, {})
+ },
+ readonlyFieldValues () {
+ return this.readonlyFields.reduce((acc, f) => {
+ acc[f.uuid] = isEmpty(this.values[f.uuid]) ? f.default_value : this.values[f.uuid]
return acc
}, {})
@@ -972,7 +981,10 @@ export default {
return this.currentStepFields[0]
},
readonlyConditionalFields () {
- return this.fields.filter((f) => f.readonly && f.conditions?.length && this.checkFieldConditions(f) && this.checkFieldDocumentsConditions(f))
+ return this.readonlyFields.filter((f) => f.conditions?.length)
+ },
+ readonlyFields () {
+ return this.fields.filter((f) => f.readonly && this.checkFieldConditions(f) && this.checkFieldDocumentsConditions(f))
},
stepFields () {
const verificationFields = []
diff --git a/app/javascript/submission_form/payment_step.vue b/app/javascript/submission_form/payment_step.vue
index b345b246..d262d3a6 100644
--- a/app/javascript/submission_form/payment_step.vue
+++ b/app/javascript/submission_form/payment_step.vue
@@ -92,10 +92,20 @@ export default {
type: Object,
required: true
},
+ readonlyValues: {
+ type: Object,
+ required: false,
+ default: () => ({})
+ },
values: {
type: Object,
required: true
},
+ fields: {
+ type: Array,
+ required: false,
+ default: () => []
+ },
submitterSlug: {
type: String,
required: true
@@ -109,6 +119,13 @@ export default {
}
},
computed: {
+ fieldsUuidIndex () {
+ return this.fields.reduce((acc, field) => {
+ acc[field.uuid] = field
+
+ return acc
+ }, {})
+ },
queryParams () {
return new URLSearchParams(window.location.search)
},
@@ -116,6 +133,10 @@ export default {
return this.queryParams.get('stripe_session_id')
},
defaultName () {
+ if (this.field.preferences?.price_id || this.field.preferences?.payment_link_id) {
+ return ''
+ }
+
const { price, currency } = this.field.preferences || {}
const formatter = new Intl.NumberFormat([], {
@@ -178,12 +199,23 @@ export default {
},
methods: {
calculateFormula () {
- const transformedFormula = this.field.preferences.formula.replace(/{{(.*?)}}/g, (match, uuid) => {
- return this.values[uuid] || 0.0
+ const transformedFormula = this.normalizeFormula(this.field.preferences.formula).replace(/{{(.*?)}}/g, (match, uuid) => {
+ return this.readonlyValues[uuid] || this.values[uuid] || 0.0
})
return this.math.evaluate(transformedFormula.toLowerCase())
},
+ normalizeFormula (formula, depth = 0) {
+ if (depth > 10) return formula
+
+ return formula.replace(/{{(.*?)}}/g, (match, uuid) => {
+ if (this.fieldsUuidIndex[uuid]) {
+ return `(${this.normalizeFormula(this.fieldsUuidIndex[uuid].preferences.formula, depth + 1)})`
+ } else {
+ return match
+ }
+ })
+ },
async submit () {
if (this.sessionId) {
return fetch(this.baseUrl + '/api/stripe_payments/' + this.sessionId, {
diff --git a/app/javascript/submission_form/verification_step.vue b/app/javascript/submission_form/verification_step.vue
index 39da2419..1f711c5e 100644
--- a/app/javascript/submission_form/verification_step.vue
+++ b/app/javascript/submission_form/verification_step.vue
@@ -14,7 +14,7 @@
{{ t('complete_all_required_fields_to_proceed_with_identity_verification') }}
@@ -100,6 +100,9 @@ export default {
}
},
computed: {
+ isRequiredFieldEmpty () {
+ return this.emptyValueRequiredStep && this.emptyValueRequiredStep[0] !== this.field
+ },
countryCode () {
const browserTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone
const browserTz = browserTimeZone.split('/')[1]
@@ -131,17 +134,19 @@ export default {
}
},
async mounted () {
- this.isLoading = true
+ if (!this.isRequiredFieldEmpty) {
+ this.isLoading = true
- if (new URLSearchParams(window.location.search).get('submit') === 'true') {
- this.$emit('submit')
- } else {
- Promise.all([
- import('@eid-easy/eideasy-widget'),
- this.start()
- ]).finally(() => {
- this.isLoading = false
- })
+ if (new URLSearchParams(window.location.search).get('submit') === 'true') {
+ this.$emit('submit')
+ } else {
+ Promise.all([
+ import('@eid-easy/eideasy-widget'),
+ this.start()
+ ]).finally(() => {
+ this.isLoading = false
+ })
+ }
}
},
methods: {
@@ -170,7 +175,7 @@ export default {
redirectUrl.searchParams.append('lang', this.locale)
this.redirectUrl = redirectUrl.toString()
- } else {
+ } else if (this.$refs.widgetContainer) {
const eidEasyWidget = document.createElement('eideasy-widget')
for (const key in this.widgetSettings) {
diff --git a/app/javascript/template_builder/area.vue b/app/javascript/template_builder/area.vue
index c786061a..d88475b3 100644
--- a/app/javascript/template_builder/area.vue
+++ b/app/javascript/template_builder/area.vue
@@ -10,7 +10,7 @@
+
+
+
+
@@ -397,6 +439,16 @@ export default {
required: false,
default: false
},
+ pageWidth: {
+ type: Number,
+ required: false,
+ default: 0
+ },
+ pageHeight: {
+ type: Number,
+ required: false,
+ default: 0
+ },
defaultSubmitters: {
type: Array,
required: false,
@@ -436,8 +488,33 @@ export default {
fieldNames: FieldType.computed.fieldNames,
fieldLabels: FieldType.computed.fieldLabels,
fieldIcons: FieldType.computed.fieldIcons,
+ bgClasses () {
+ if (this.field.type === 'heading') {
+ return 'bg-gray-50'
+ } else if (this.field.type === 'strikethrough') {
+ return 'bg-transparent'
+ } else {
+ return this.bgColors[this.submitterIndex % this.bgColors.length]
+ }
+ },
+ activeBorderClasses () {
+ if (this.field.type === 'heading') {
+ return ''
+ } else if (this.field.type === 'strikethrough') {
+ return 'border-dashed border-gray-300'
+ } else {
+ return this.borderColors[this.submitterIndex % this.borderColors.length]
+ }
+ },
isWFullType () {
- return ['cells', 'checkbox', 'radio', 'multiple', 'select'].includes(this.field.type)
+ return ['cells', 'checkbox', 'radio', 'multiple', 'select', 'strikethrough'].includes(this.field.type)
+ },
+ strikethroughWidth () {
+ if (this.isInlineSize) {
+ return '0.6cqmin'
+ } else {
+ return 'clamp(0px, 0.5vw, 6px)'
+ }
},
fontStyle () {
let fontSize = ''
@@ -471,8 +548,11 @@ export default {
lineHeight () {
return 1.3
},
+ basePageWidth () {
+ return 1040.0
+ },
fontScale () {
- return 1040 / 612.0
+ return this.basePageWidth / 612.0
},
isDefaultValuePresent () {
return this.field?.default_value || this.field?.default_value === 0
@@ -742,8 +822,13 @@ export default {
delete this.field.options
}
- if (['heading'].includes(this.field.type)) {
+ if (this.field.type === 'heading') {
+ this.field.readonly = true
+ }
+
+ if (this.field.type === 'strikethrough') {
this.field.readonly = true
+ this.field.default_value = true
}
if (['select', 'multiple', 'radio'].includes(this.field.type)) {
diff --git a/app/javascript/template_builder/builder.vue b/app/javascript/template_builder/builder.vue
index a9f3709b..c679a37e 100644
--- a/app/javascript/template_builder/builder.vue
+++ b/app/javascript/template_builder/builder.vue
@@ -402,7 +402,10 @@
:style="{ backgroundColor }"
>
-
+
+ {{ t('draw_strikethrough_the_document') }}
+
+
{{ t('draw_field_on_the_document') }}
@@ -413,7 +416,7 @@
{{ t('cancel') }}
{
- if (f !== this.item && (!f.conditions?.length || !f.conditions.find((c) => c.field_uuid === this.item.uuid))) {
+ if (f !== this.item && !this.excludeTypes.includes(f.type) && (!f.conditions?.length || !f.conditions.find((c) => c.field_uuid === this.item.uuid))) {
acc.push(f)
}
diff --git a/app/javascript/template_builder/field.vue b/app/javascript/template_builder/field.vue
index d8b6538e..04bb9e01 100644
--- a/app/javascript/template_builder/field.vue
+++ b/app/javascript/template_builder/field.vue
@@ -14,7 +14,7 @@
f.type === field.type).indexOf(field)
- if (field.type === 'heading') {
+ if (field.type === 'heading' || field.type === 'strikethrough') {
return `${this.fieldNames[field.type]} ${typeIndex + 1}`
} else {
return `${this.fieldLabels[field.type]} ${typeIndex + 1}`
@@ -485,8 +485,13 @@ export default {
this.field.options ||= [{ value: '', uuid: v4() }]
}
- if (['heading'].includes(this.field.type)) {
+ if (this.field.type === 'heading') {
+ this.field.readonly = true
+ }
+
+ if (this.field.type === 'strikethrough') {
this.field.readonly = true
+ this.field.default_value = true
}
(this.field.areas || []).forEach((area) => {
diff --git a/app/javascript/template_builder/field_settings.vue b/app/javascript/template_builder/field_settings.vue
index f446bca7..d3e2e842 100644
--- a/app/javascript/template_builder/field_settings.vue
+++ b/app/javascript/template_builder/field_settings.vue
@@ -380,7 +380,7 @@
-
×
+
×
diff --git a/app/views/shared/_github.html.erb b/app/views/shared/_github.html.erb
index df415db6..c07cc7cc 100644
--- a/app/views/shared/_github.html.erb
+++ b/app/views/shared/_github.html.erb
@@ -1,6 +1,6 @@
<%= svg_icon('start', class: 'h-3 w-3') %>
- 9k
+ 10k
diff --git a/app/views/shared/_navbar.html.erb b/app/views/shared/_navbar.html.erb
index dd124e46..6d66674c 100644
--- a/app/views/shared/_navbar.html.erb
+++ b/app/views/shared/_navbar.html.erb
@@ -61,7 +61,9 @@
<% if (can?(:manage, EncryptedConfig) && current_user == true_user) || (current_user != true_user && current_account.testing?) %>
<%= form_for '', url: testing_account_path, method: current_account.testing? ? :delete : :get, html: { class: 'w-full py-1' } do |f| %>
- <%= f.check_box :testing_toggle, class: 'toggle', checked: current_account.testing?, onchange: 'this.form.requestSubmit()', style: 'height: 0.885rem; width: 1.35rem; --handleoffset: 0.395rem; margin-left: -2px; margin-right: 8px' %>
+
+ <%= f.check_box :testing_toggle, class: 'toggle', checked: current_account.testing?, style: 'height: 0.885rem; width: 1.35rem; --handleoffset: 0.395rem; margin-left: -2px; margin-right: 8px' %>
+
<%= t('test_mode') %>
diff --git a/app/views/shared/_search_input.html.erb b/app/views/shared/_search_input.html.erb
index 5a6fae26..f9c935f8 100644
--- a/app/views/shared/_search_input.html.erb
+++ b/app/views/shared/_search_input.html.erb
@@ -14,15 +14,15 @@
<% end %>
-
+
+
-
diff --git a/app/views/shared/_settings_nav.html.erb b/app/views/shared/_settings_nav.html.erb
index 64fc1c9c..1b06a08a 100644
--- a/app/views/shared/_settings_nav.html.erb
+++ b/app/views/shared/_settings_nav.html.erb
@@ -98,7 +98,9 @@
<%= t('test_mode') %>
- <%= f.check_box :testing_toggle, class: 'toggle toggle-sm', checked: current_account.testing?, onchange: 'this.form.requestSubmit()' %>
+
+ <%= f.check_box :testing_toggle, class: 'toggle toggle-sm', checked: current_account.testing? %>
+
<% end %>
diff --git a/app/views/shared/_test_mode_toggle.html.erb b/app/views/shared/_test_mode_toggle.html.erb
index c53a713e..f74dd1ce 100644
--- a/app/views/shared/_test_mode_toggle.html.erb
+++ b/app/views/shared/_test_mode_toggle.html.erb
@@ -4,7 +4,9 @@
<%= t('test_mode') %>
- <%= f.check_box :testing_toggle, class: 'toggle', checked: current_account.testing?, onchange: 'this.form.requestSubmit()' %>
+
+ <%= f.check_box :testing_toggle, class: 'toggle', checked: current_account.testing? %>
+
<% end %>
<% end %>
diff --git a/app/views/start_form/show.html.erb b/app/views/start_form/show.html.erb
index 75c42e28..271b50c1 100644
--- a/app/views/start_form/show.html.erb
+++ b/app/views/start_form/show.html.erb
@@ -52,7 +52,9 @@
<% if link_form_fields.include?('phone') %>
<%= f.label :phone, t('phone'), class: 'label' %>
- <%= f.telephone_field :phone, value: params[:phone] || @submitter.phone, pattern: '^\+[0-9\s\-]+$', oninvalid: "this.value ? this.setCustomValidity('#{t('use_international_format_1xxx_')}') : ''", oninput: "this.setCustomValidity('')", required: true, class: 'base-input', placeholder: t(multiple_fields ? 'provide_your_phone_in_international_format' : 'provide_your_phone_in_international_format_to_start') %>
+
+ <%= f.telephone_field :phone, value: params[:phone] || @submitter.phone, pattern: '^\+[0-9\s\-]+$', required: true, class: 'base-input w-full', placeholder: t(multiple_fields ? 'provide_your_phone_in_international_format' : 'provide_your_phone_in_international_format_to_start') %>
+
<% end %>
diff --git a/app/views/submissions/_detailed_form.html.erb b/app/views/submissions/_detailed_form.html.erb
index dd4f9d99..b2c79997 100644
--- a/app/views/submissions/_detailed_form.html.erb
+++ b/app/views/submissions/_detailed_form.html.erb
@@ -33,11 +33,13 @@
<% has_phone_field = true %>
-
- ">
- <%= tag.input type: 'tel', pattern: '^\+[0-9\s\-]+$', oninvalid: "this.value ? this.setCustomValidity('#{t('use_international_format_1xxx_')}') : ''", oninput: "this.setCustomValidity('')", name: 'submission[1][submitters][][phone]', autocomplete: 'off', class: 'base-input !h-10 mt-1.5 w-full', placeholder: local_assigns[:require_phone_2fa] == true ? t(:phone) : "#{t('phone')} (#{t('optional')})", id: "detailed_phone_#{item['uuid']}", required: local_assigns[:require_phone_2fa] == true %>
-
-
+
+
+ ">
+ <%= tag.input type: 'tel', pattern: '^\+[0-9\s\-]+$', autocomplete: 'off', class: 'base-input !h-10 mt-1.5 w-full', placeholder: local_assigns[:require_phone_2fa] == true ? t(:phone) : "#{t('phone')} (#{t('optional')})", id: "detailed_phone_#{item['uuid']}", required: local_assigns[:require_phone_2fa] == true %>
+
+
+
<% end %>
<% if prefillable_fields.present? %>
@@ -48,11 +50,13 @@
<% if local_assigns[:require_phone_2fa] == true || prefillable_fields.any? { |f| f['type'] == 'phone' } %>
<% has_phone_field = true %>
-
- ">
- <%= tag.input type: 'tel', pattern: '^\+[0-9\s\-]+$', oninvalid: "this.value ? this.setCustomValidity('#{t('use_international_format_1xxx_')}') : ''", oninput: "this.setCustomValidity('')", name: 'submission[1][submitters][][phone]', autocomplete: 'off', class: 'base-input !h-10 mt-1.5 w-full', placeholder: t(:phone), id: "detailed_phone_#{item['uuid']}", required: true %>
-
-
+
+
+ ">
+ <%= tag.input type: 'tel', pattern: '^\+[0-9\s\-]+$', name: 'submission[1][submitters][][phone]', autocomplete: 'off', class: 'base-input !h-10 mt-1.5 w-full', placeholder: t(:phone), id: "detailed_phone_#{item['uuid']}", required: true %>
+
+
+
<% end %>
<% prefillable_fields.each do |field| %>
<% if field['type'] == 'checkbox' %>
diff --git a/app/views/submissions/_phone_form.html.erb b/app/views/submissions/_phone_form.html.erb
index 649739fc..305f6e87 100644
--- a/app/views/submissions/_phone_form.html.erb
+++ b/app/views/submissions/_phone_form.html.erb
@@ -19,11 +19,13 @@
<% end %>
-
- ">
- <%= tag.input type: 'tel', pattern: '^\+[0-9\s\-]+$', oninvalid: "this.value ? this.setCustomValidity('#{t('use_international_format_1xxx_')}') : ''", oninput: "this.setCustomValidity('')", name: 'submission[1][submitters][][phone]', autocomplete: 'off', class: 'base-input !h-10 w-full', placeholder: t('phone'), required: index.zero? || template.preferences['require_all_submitters'], id: "phone_phone_#{item['uuid']}" %>
-
-
+
+
+ ">
+ <%= tag.input type: 'tel', pattern: '^\+[0-9\s\-]+$', name: 'submission[1][submitters][][phone]', autocomplete: 'off', class: 'base-input !h-10 w-full', placeholder: t('phone'), required: index.zero? || template.preferences['require_all_submitters'], id: "phone_phone_#{item['uuid']}" %>
+
+
+
<% if submitters.size > 1 %>
">
diff --git a/app/views/submissions/_send_email.html.erb b/app/views/submissions/_send_email.html.erb
index d7f357c0..f9251baf 100644
--- a/app/views/submissions/_send_email.html.erb
+++ b/app/views/submissions/_send_email.html.erb
@@ -11,10 +11,12 @@
<% if can_send_emails %>
<%= render 'submissions/email_stats' %>
<%= content_for(:edit_button) || capture do %>
-
- <%= f.check_box :is_custom_message, onchange: "[this.form.querySelector('#message_field').classList.toggle('hidden', !event.currentTarget.checked)]", checked: false, class: 'hidden peer' %>
- <%= t('edit_message') %>
-
+
+
+ <%= f.check_box :is_custom_message, checked: false, class: 'hidden peer', data: { action: 'change:toggle-visible#trigger', type: 'checkbox' } %>
+ <%= t('edit_message') %>
+
+
<% end %>
<% end %>
diff --git a/app/views/submissions/_value.html.erb b/app/views/submissions/_value.html.erb
index 81158cdb..025053ef 100644
--- a/app/views/submissions/_value.html.erb
+++ b/app/views/submissions/_value.html.erb
@@ -76,6 +76,19 @@
<%= NumberUtils.format_number(value, field.dig('preferences', 'format')) %>
+ <% elsif field['type'] == 'strikethrough' %>
+
+ <% if (((1000.0 / local_assigns[:page_width]) * local_assigns[:page_height]) * area['h']) < 40 %>
+
+ <% else %>
+
+ <% end %>
+
<% else %>
@@ -123,7 +123,7 @@
<% else %>
- <%= render 'submissions/value', font_scale:, area:, field:, attachments_index:, value: mask.present? ? Array.wrap(value).map { |e| TextUtils.mask_value(e, mask) }.join(', ') : value, locale: @submission.account.locale, timezone: @submission.account.timezone, submitter:, with_signature_id:, with_submitter_timezone:, with_signature_id_reason: %>
+ <%= render 'submissions/value', page_width: width, page_height: height, font_scale:, area:, field:, attachments_index:, value: mask.present? ? Array.wrap(value).map { |e| TextUtils.mask_value(e, mask) }.join(', ') : value, locale: @submission.account.locale, timezone: @submission.account.timezone, submitter:, with_signature_id:, with_submitter_timezone:, with_signature_id_reason: %>
<% end %>
<% end %>
@@ -240,7 +240,7 @@
<% submitter_field_counters[field['type']] += 1 %>
<% value = values[field['uuid']].presence || (field['default_value'] != '{{date}}' && field['readonly'] == true && field['default_value'].present? ? Submitters::SubmitValues.template_default_value_for_submitter(field['default_value'], @submission.submitters.find { |e| e.uuid == field['submitter_uuid'] }, with_time: false) : nil) %>
<% next if value.blank? %>
- <% next if field['type'] == 'heading' %>
+ <% next if field['type'] == 'heading' || field['type'] == 'strikethrough' %>
<%= field['name'].presence || "#{t("#{field['type']}_field")} #{submitter_field_counters[field['type']]}" %>
@@ -288,16 +288,20 @@
<% end %>
-
-
-
- <%= svg_icon('users', class: 'w-8 h-8') %>
- <%= t('signers') %>
-
-
- <%= svg_icon('chevron_left', class: 'w-8 h-8') %>
- <%= t('back') %>
-
-
+
+
+
+
+ <%= svg_icon('users', class: 'w-8 h-8') %>
+ <%= t('signers') %>
+
+
+ <%= svg_icon('chevron_left', class: 'w-8 h-8') %>
+ <%= t('back') %>
+
+
+
-<%= render 'scripts/autosize_field' %>
+<% unless request.headers['HTTP_X_TURBO'] %>
+ <%= render 'scripts/autosize_field' %>
+<% end %>
diff --git a/app/views/submit_form/show.html.erb b/app/views/submit_form/show.html.erb
index 1649b848..04be2c7f 100644
--- a/app/views/submit_form/show.html.erb
+++ b/app/views/submit_form/show.html.erb
@@ -84,7 +84,7 @@
<% next if field['conditions'].present? && values[field['uuid']].blank? && field['submitter_uuid'] != @submitter.uuid %>
<% next if field['conditions'].present? && field['submitter_uuid'] == @submitter.uuid %>
<% next if field.dig('preferences', 'formula').present? && field['submitter_uuid'] == @submitter.uuid %>
- <%= render 'submissions/value', font_scale:, area:, field:, attachments_index: @attachments_index, value: field.dig('preferences', 'mask').present? ? TextUtils.mask_value(value, field.dig('preferences', 'mask')) : value, locale: @submitter.account.locale, timezone: @submitter.account.timezone, submitter: submitters_index[field['submitter_uuid']], with_signature_id: @form_configs[:with_signature_id], with_submitter_timezone: @form_configs[:with_submitter_timezone], with_signature_id_reason: @form_configs[:with_signature_id_reason] %>
+ <%= render 'submissions/value', page_width: width, page_height: height, font_scale:, area:, field:, attachments_index: @attachments_index, value: field.dig('preferences', 'mask').present? ? TextUtils.mask_value(value, field.dig('preferences', 'mask')) : value, locale: @submitter.account.locale, timezone: @submitter.account.timezone, submitter: submitters_index[field['submitter_uuid']], with_signature_id: @form_configs[:with_signature_id], with_submitter_timezone: @form_configs[:with_submitter_timezone], with_signature_id_reason: @form_configs[:with_signature_id_reason] %>
<% end %>
diff --git a/app/views/submit_form_draw_signature/show.html.erb b/app/views/submit_form_draw_signature/show.html.erb
index 1ab495ed..f1ffebf0 100644
--- a/app/views/submit_form_draw_signature/show.html.erb
+++ b/app/views/submit_form_draw_signature/show.html.erb
@@ -4,7 +4,6 @@
<%= render 'layouts/head_tags' %>
<%= csrf_meta_tags %>
- <%= csp_meta_tag %>
<% if ENV['ROLLBAR_CLIENT_TOKEN'] %>
<%= javascript_pack_tag 'rollbar', 'draw', defer: true %>
diff --git a/app/views/submitters/edit.html.erb b/app/views/submitters/edit.html.erb
index eb309c9e..a4f69f9b 100644
--- a/app/views/submitters/edit.html.erb
+++ b/app/views/submitters/edit.html.erb
@@ -10,9 +10,11 @@
<%= email_field_tag 'submitter[email]', @submitter.email, autocomplete: 'off', class: 'base-input !h-10 mt-1.5 w-full', placeholder: "#{t('email')} (#{t('optional')})" %>
-
- <%= telephone_field_tag 'submitter[phone]', @submitter.phone, autocomplete: 'off', pattern: '^\+[0-9\s\-]+$', class: 'base-input !h-10 mt-1.5 w-full', placeholder: "#{t('phone')} (#{t('optional')})", oninvalid: "this.value ? this.setCustomValidity('#{t('use_international_format_1xxx_')}') : ''", oninput: "this.setCustomValidity('')" %>
-
+
+
+ <%= telephone_field_tag 'submitter[phone]', @submitter.phone, autocomplete: 'off', pattern: '^\+[0-9\s\-]+$', class: 'base-input !h-10 mt-1.5 w-full', placeholder: "#{t('phone')} (#{t('optional')})" %>
+
+
diff --git a/app/views/template_folders/show.html.erb b/app/views/template_folders/show.html.erb
index 2f6ac8ea..c51879d8 100644
--- a/app/views/template_folders/show.html.erb
+++ b/app/views/template_folders/show.html.erb
@@ -34,7 +34,9 @@
<%= render 'shared/search_input' %>
<% end %>
<% if can?(:create, ::Template) %>
- <%= render 'templates/upload_button', folder_name: @template_folder.full_name %>
+
+ <%= render 'templates/upload_button', folder_name: @template_folder.full_name %>
+
<%= link_to new_template_path(folder_name: @template_folder.full_name), class: 'white-button !border gap-2', data: { turbo_frame: :modal } do %>
<%= svg_icon('plus', class: 'w-6 h-6 stroke-2') %>
<%= t('create') %>
diff --git a/app/views/templates/_upload_button.html.erb b/app/views/templates/_upload_button.html.erb
index 40460070..4b7156aa 100644
--- a/app/views/templates/_upload_button.html.erb
+++ b/app/views/templates/_upload_button.html.erb
@@ -1,19 +1,22 @@
<%= form_for '', url: templates_upload_path, id: form_id = SecureRandom.uuid, method: :post, class: 'inline', html: { enctype: 'multipart/form-data' } do %>
-
+
- " multiple>
+
+ " multiple>
+
<% end %>
diff --git a/app/views/templates/new.html.erb b/app/views/templates/new.html.erb
index c55ef24a..d3a3febc 100644
--- a/app/views/templates/new.html.erb
+++ b/app/views/templates/new.html.erb
@@ -12,14 +12,18 @@
<%= f.text_field :name, required: true, placeholder: t('document_name'), class: 'base-input', dir: 'auto' %>
diff --git a/app/views/templates_code_modal/show.html.erb b/app/views/templates_code_modal/show.html.erb
index 96b69cd3..46e9c893 100644
--- a/app/views/templates_code_modal/show.html.erb
+++ b/app/views/templates_code_modal/show.html.erb
@@ -25,7 +25,9 @@
<%= t('share_template_with_test_mode') %>
- <%= f.check_box :value, class: 'toggle', checked: @template.template_sharings.exists?(account_id: current_account.testing_accounts), onchange: 'this.form.requestSubmit()' %>
+
+ <%= f.check_box :value, class: 'toggle', checked: @template.template_sharings.exists?(account_id: current_account.testing_accounts) %>
+
<% end %>
diff --git a/app/views/templates_dashboard/index.html.erb b/app/views/templates_dashboard/index.html.erb
index d8509885..449fa49f 100644
--- a/app/views/templates_dashboard/index.html.erb
+++ b/app/views/templates_dashboard/index.html.erb
@@ -63,7 +63,7 @@
<% if user_config.new_record? && !params.key?(:tour) %>
-
+
<%= t('welcome_to_docuseal') %>
@@ -71,8 +71,12 @@
<%= t('start_a_quick_tour_to_learn_how_to_create_an_send_your_first_document') %>
- <%= button_to button_title(title: t('skip'), icon_disabled: svg_icon('loader', class: 'w-4 h-4 animate-spin')), user_configs_path, params: { user_config: { key: UserConfig::SHOW_APP_TOUR, value: false } }, class: 'btn btn-sm btn-outline w-full', form_class: 'flex-1', method: :post, form: { onsubmit: 'window.app_tour.parentNode.remove()' } %>
- <%= button_to t('start_tour'), user_configs_path, params: { user_config: { key: UserConfig::SHOW_APP_TOUR, value: true } }, class: 'btn btn-sm btn-warning w-full', form_class: 'flex-1', method: :post, form: { onsubmit: 'window.app_tour.start()' } %>
+
+ <%= button_to button_title(title: t('skip'), icon_disabled: svg_icon('loader', class: 'w-4 h-4 animate-spin')), user_configs_path, params: { user_config: { key: UserConfig::SHOW_APP_TOUR, value: false } }, class: 'btn btn-sm btn-outline w-full', form_class: 'flex-1', method: :post %>
+
+
+ <%= button_to t('start_tour'), user_configs_path, params: { user_config: { key: UserConfig::SHOW_APP_TOUR, value: true } }, class: 'btn btn-sm btn-warning w-full', form_class: 'flex-1', method: :post %>
+
<% end %>
diff --git a/app/views/templates_form_preview/show.html.erb b/app/views/templates_form_preview/show.html.erb
index 6b5c49c7..c40457cb 100644
--- a/app/views/templates_form_preview/show.html.erb
+++ b/app/views/templates_form_preview/show.html.erb
@@ -6,13 +6,15 @@
<% if @template.submitters.size > 1 %>
<% end %>
diff --git a/app/views/templates_preferences/_recipients.html.erb b/app/views/templates_preferences/_recipients.html.erb
index 81bf71fa..a8547669 100644
--- a/app/views/templates_preferences/_recipients.html.erb
+++ b/app/views/templates_preferences/_recipients.html.erb
@@ -73,7 +73,9 @@
<%= t('enforce_recipients_order') %>
<%= f.fields_for :preferences, Struct.new(:submitters_order).new(template.preferences['submitters_order']) do |ff| %>
- <%= ff.check_box :submitters_order, { class: 'toggle', onchange: 'this.form.requestSubmit()' }, 'preserved', '' %>
+
+ <%= ff.check_box :submitters_order, { class: 'toggle' }, 'preserved', '' %>
+
<% end %>
<% end %>
@@ -85,7 +87,9 @@
<%= t('ensure_unique_recipients') %>
<%= f.fields_for :preferences, Struct.new(:validate_unique_submitters).new(template.preferences['validate_unique_submitters']) do |ff| %>
- <%= ff.check_box :validate_unique_submitters, { class: 'toggle', onchange: 'this.form.requestSubmit()' }, 'true', '' %>
+
+ <%= ff.check_box :validate_unique_submitters, { class: 'toggle' }, 'true', '' %>
+
<% end %>
<% end %>
diff --git a/app/views/templates_preferences/show.html.erb b/app/views/templates_preferences/show.html.erb
index 0c77ca43..54f8d83f 100644
--- a/app/views/templates_preferences/show.html.erb
+++ b/app/views/templates_preferences/show.html.erb
@@ -46,9 +46,13 @@
<% end %>
@@ -215,19 +221,25 @@
<%= t('attach_documents_to_the_email') %>
- <%= ff.check_box :documents_copy_email_attach_documents, { checked: ff.object.documents_copy_email_attach_documents != false, class: 'toggle', onchange: 'this.form.requestSubmit()', disabled: configs['attach_documents'] == false }, 'true', 'false' %>
+
+ <%= ff.check_box :documents_copy_email_attach_documents, { checked: ff.object.documents_copy_email_attach_documents != false, class: 'toggle', disabled: configs['attach_documents'] == false }, 'true', 'false' %>
+
<%= t('attach_audit_log_pdf_to_the_email') %>
- <%= ff.check_box :documents_copy_email_attach_audit, { checked: ff.object.documents_copy_email_attach_audit != false, class: 'toggle', onchange: 'this.form.requestSubmit()', disabled: configs['attach_audit_log'] == false }, 'true', 'false' %>
+
+ <%= ff.check_box :documents_copy_email_attach_audit, { checked: ff.object.documents_copy_email_attach_audit != false, class: 'toggle', disabled: configs['attach_audit_log'] == false }, 'true', 'false' %>
+
<%= t('send_emails_automatically_on_completion') %>
- <%= ff.check_box :documents_copy_email_enabled, { checked: ff.object.documents_copy_email_enabled != false && configs['enabled'] != false, class: 'toggle', onchange: 'this.form.requestSubmit()', disabled: configs['enabled'] == false }, 'true', 'false' %>
+
+ <%= ff.check_box :documents_copy_email_enabled, { checked: ff.object.documents_copy_email_enabled != false && configs['enabled'] != false, class: 'toggle', disabled: configs['enabled'] == false }, 'true', 'false' %>
+
<% end %>
@@ -268,19 +280,25 @@
<%= t('attach_documents_to_the_email') %>
- <%= ff.check_box :completed_notification_email_attach_documents, { checked: ff.object.completed_notification_email_attach_documents != false, class: 'toggle', onchange: 'this.form.requestSubmit()', disabled: configs['attach_documents'] == false }, 'true', 'false' %>
+
+ <%= ff.check_box :completed_notification_email_attach_documents, { checked: ff.object.completed_notification_email_attach_documents != false, class: 'toggle', disabled: configs['attach_documents'] == false }, 'true', 'false' %>
+
<%= t('attach_audit_log_pdf_to_the_email') %>
- <%= ff.check_box :completed_notification_email_attach_audit, { checked: ff.object.completed_notification_email_attach_audit != false, class: 'toggle', onchange: 'this.form.requestSubmit()', disabled: configs['attach_audit_log'] == false }, 'true', 'false' %>
+
+ <%= ff.check_box :completed_notification_email_attach_audit, { checked: ff.object.completed_notification_email_attach_audit != false, class: 'toggle', disabled: configs['attach_audit_log'] == false }, 'true', 'false' %>
+
<%= t('send_emails_automatically_on_completion') %>
- <%= ff.check_box :completed_notification_email_enabled, { checked: ff.object.completed_notification_email_enabled != false, class: 'toggle', onchange: 'this.form.requestSubmit()' }, 'true', 'false' %>
+
+ <%= ff.check_box :completed_notification_email_enabled, { checked: ff.object.completed_notification_email_enabled != false, class: 'toggle', disabled: configs['enabled'] == false }, 'true', 'false' %>
+
<% end %>
@@ -325,7 +343,9 @@
<%= t('enable_shared_link') %>
- <%= f.check_box :shared_link, { class: 'toggle', onchange: 'this.form.requestSubmit()' }, 'true', 'false' %>
+
+ <%= f.check_box :shared_link, { class: 'toggle' }, 'true', 'false' %>
+
<% end %>
@@ -339,7 +359,9 @@
<%= t('share_template_with_test_mode') %>
- <%= f.check_box :value, class: 'toggle', checked: @template.template_sharings.exists?(account_id: current_account.testing_accounts), onchange: 'this.form.requestSubmit()' %>
+
+ <%= f.check_box :value, class: 'toggle', checked: @template.template_sharings.exists?(account_id: current_account.testing_accounts) %>
+
<% end %>
diff --git a/app/views/templates_share_link/show.html.erb b/app/views/templates_share_link/show.html.erb
index df1ad45e..fed24fe0 100644
--- a/app/views/templates_share_link/show.html.erb
+++ b/app/views/templates_share_link/show.html.erb
@@ -5,7 +5,9 @@
<%= form_for @template, url: template_share_link_path(@template), method: :post, html: { id: 'shared_link_form', autocomplete: 'off', class: 'mt-3' }, data: { close_on_submit: false } do |f| %>
<%= t('enable_shared_link') %>
- <%= f.check_box :shared_link, { disabled: !can?(:update, @template), class: 'toggle', onchange: 'this.form.requestSubmit()' }, 'true', 'false' %>
+
+ <%= f.check_box :shared_link, { disabled: !can?(:update, @template), class: 'toggle' }, 'true', 'false' %>
+
@@ -63,7 +65,9 @@
<%= f.fields_for :preferences, Struct.new(:shared_link_2fa).new(@template.preferences['shared_link_2fa'] == true) do |ff| %>
<%= t('request_email_otp_verification_with_shared_link') %>
- <%= ff.check_box :shared_link_2fa, { checked: ff.object.shared_link_2fa == true, disabled: !can?(:update, @template), class: 'toggle', onchange: 'this.form.requestSubmit()' }, 'true', 'false' %>
+
+ <%= ff.check_box :shared_link_2fa, { checked: ff.object.shared_link_2fa == true, disabled: !can?(:update, @template), class: 'toggle' }, 'true', 'false' %>
+
<% end %>
<% end %>
diff --git a/app/views/webhook_events/_drawer_events.html.erb b/app/views/webhook_events/_drawer_events.html.erb
index 275259c6..9858be96 100644
--- a/app/views/webhook_events/_drawer_events.html.erb
+++ b/app/views/webhook_events/_drawer_events.html.erb
@@ -51,7 +51,9 @@
<% unless webhook_event.status == 'pending' %>
- <%= button_to button_title(title: t('resend'), disabled_with: t('awaiting'), icon: svg_icon('rotate', class: 'w-4 h-4'), icon_disabled: svg_icon('loader', class: 'w-4 h-4 animate-spin')), resend_settings_webhook_event_path(webhook_url.id, webhook_event.uuid), form: { id: button_uuid = SecureRandom.uuid }, params: { button_id: button_uuid }, class: 'btn btn-neutral btn-sm text-white', method: :post, onclick: '[this.form.requestSubmit(), this.disabled = true]' %>
+
+ <%= button_to button_title(title: t('resend'), disabled_with: t('awaiting'), icon: svg_icon('rotate', class: 'w-4 h-4'), icon_disabled: svg_icon('loader', class: 'w-4 h-4 animate-spin')), resend_settings_webhook_event_path(webhook_url.id, webhook_event.uuid), form: { id: button_uuid = SecureRandom.uuid }, params: { button_id: button_uuid }, class: 'btn btn-neutral btn-sm text-white', method: :post %>
+
<% end %>
diff --git a/app/views/webhook_events/_event_row.html.erb b/app/views/webhook_events/_event_row.html.erb
index a6af3020..2b45f393 100644
--- a/app/views/webhook_events/_event_row.html.erb
+++ b/app/views/webhook_events/_event_row.html.erb
@@ -21,7 +21,9 @@
<%= webhook_event.event_type %>
- <%= button_to button_title(title: t('resend'), disabled_with: t('awaiting'), icon: svg_icon('rotate', class: 'w-4 h-4'), icon_disabled: svg_icon('loader', class: 'w-4 h-4 animate-spin')), resend_settings_webhook_event_path(webhook_url.id, webhook_event.uuid), form: { id: button_uuid = SecureRandom.uuid }, params: { button_id: button_uuid }, class: 'btn btn-neutral btn-xs h-2 text-white relative z-[1] hidden md:group-hover:inline-block', data: { turbo_frame: :drawer }, method: :post, onclick: "[this.form.requestSubmit(), this.disabled = true, this.classList.remove('hidden')]" %>
+
+ <%= button_to button_title(title: t('resend'), disabled_with: t('awaiting'), icon: svg_icon('rotate', class: 'w-4 h-4'), icon_disabled: svg_icon('loader', class: 'w-4 h-4 animate-spin')), resend_settings_webhook_event_path(webhook_url.id, webhook_event.uuid), form: { id: button_uuid = SecureRandom.uuid }, params: { button_id: button_uuid }, class: 'btn btn-neutral btn-xs h-2 text-white relative z-[1] hidden md:group-hover:inline-block', data: { turbo_frame: :drawer }, method: :post %>
+
<%= l(webhook_event.created_at, locale: current_account.locale, format: :short) %>
diff --git a/app/views/webhook_settings/show.html.erb b/app/views/webhook_settings/show.html.erb
index 5084319e..38b08f2c 100644
--- a/app/views/webhook_settings/show.html.erb
+++ b/app/views/webhook_settings/show.html.erb
@@ -66,7 +66,9 @@
<%= f.fields_for :events do |ff| %>
- <%= ff.check_box event, class: 'base-checkbox', checked: @webhook_url.events.include?(event), onchange: 'this.form.requestSubmit()' %>
+
+ <%= ff.check_box event, class: 'base-checkbox', checked: @webhook_url.events.include?(event) %>
+
<%= event %>
diff --git a/config/application.rb b/config/application.rb
index 8021f58a..4ba83e90 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -31,6 +31,9 @@ module DocuSeal
config.exceptions_app = ->(env) { ErrorsController.action(:show).call(env) }
+ config.content_security_policy_nonce_generator = ->(_) { SecureRandom.base64(16) }
+ config.content_security_policy_nonce_directives = %w[script-src]
+
config.action_view.frozen_string_literal = true
config.middleware.insert_before ActionDispatch::Static, Rack::Deflater
diff --git a/config/environments/development.rb b/config/environments/development.rb
index b806a14f..bc9dc2d4 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -66,6 +66,8 @@ Rails.application.configure do
# Raise exceptions for disallowed deprecations.
config.active_support.disallowed_deprecation = :raise
+ config.active_storage.service_urls_expire_in = 240.minutes
+
# Tell Active Support which deprecation messages to disallow.
config.active_support.disallowed_deprecation_warnings = []
diff --git a/config/locales/i18n.yml b/config/locales/i18n.yml
index eaf10d7f..ac1b8ebd 100644
--- a/config/locales/i18n.yml
+++ b/config/locales/i18n.yml
@@ -27,6 +27,7 @@ en: &en
enabled: Enabled
disabled: Disabled
party: Party
+ use_direct_file_attachment_links_in_the_documents: Use direct file attachment links in the documents
click_here_to_send_a_reset_password_email_html: 'Click here to send a reset password email.'
edit_order: Edit Order
expirable_file_download_links: Expirable file download links
@@ -592,6 +593,8 @@ en: &en
four_days: 4 days
eight_days: 8 days
fifteen_days: 15 days
+ twenty_one_days: 21 days
+ thirty_days: 30 days
free: Free
unlimited_documents_storage: Unlimited documents storage
users_management: Users management
@@ -932,6 +935,7 @@ en: &en
range_without_total: "%{from}-%{to} events"
es: &es
+ use_direct_file_attachment_links_in_the_documents: Usar enlaces directos de archivos adjuntos en los documentos
enabled: Habilitado
disabled: Deshabilitado
expirable_file_download_links: Enlaces de descarga de archivos con vencimiento
@@ -1504,6 +1508,8 @@ es: &es
four_days: 4 días
eight_days: 8 días
fifteen_days: 15 días
+ twenty_one_days: 21 días
+ thirty_days: 30 días
free: Gratis
unlimited_documents_storage: Almacenamiento ilimitado de documentos
users_management: Gestión de usuarios
@@ -1843,6 +1849,7 @@ es: &es
range_without_total: "%{from}-%{to} eventos"
it: &it
+ use_direct_file_attachment_links_in_the_documents: Usa i link diretti per gli allegati nei documenti
click_here_to_send_a_reset_password_email_html: 'Clicca qui per inviare una email per reimpostare la password.'
enabled: Abilitato
disabled: Disabilitato
@@ -2414,6 +2421,8 @@ it: &it
four_days: 4 giorni
eight_days: 8 giorni
fifteen_days: 15 giorni
+ twenty_one_days: 21 giorni
+ thirty_days: 30 giorni
free: Gratuito
unlimited_documents_storage: Archiviazione illimitata di documenti
users_management: Gestione utenti
@@ -2755,6 +2764,7 @@ it: &it
range_without_total: "%{from}-%{to} eventi"
fr: &fr
+ use_direct_file_attachment_links_in_the_documents: Utiliser des liens directs pour les pièces jointes dans les documents
click_here_to_send_a_reset_password_email_html: 'Cliquez ici pour envoyer un e-mail de réinitialisation du mot de passe.'
enabled: Activé
disabled: Désactivé
@@ -3329,6 +3339,8 @@ fr: &fr
four_days: 4 jours
eight_days: 8 jours
fifteen_days: 15 jours
+ twenty_one_days: 21 jours
+ thirty_days: 30 jours
free: Gratuit
unlimited_documents_storage: Stockage illimité de documents
users_management: Gestion des utilisateurs
@@ -3670,6 +3682,7 @@ fr: &fr
range_without_total: "%{from} à %{to} événements"
pt: &pt
+ use_direct_file_attachment_links_in_the_documents: Usar links diretos de anexos de arquivos nos documentos
click_here_to_send_a_reset_password_email_html: 'Clique aqui para enviar um e-mail de redefinição de senha.'
enabled: Ativado
disabled: Desativado
@@ -4243,6 +4256,8 @@ pt: &pt
four_days: 4 dias
eight_days: 8 dias
fifteen_days: 15 dias
+ twenty_one_days: 21 dias
+ thirty_days: 30 dias
free: Gratuito
unlimited_documents_storage: Armazenamento ilimitado de documentos
users_management: Gerenciamento de usuários
@@ -4583,6 +4598,7 @@ pt: &pt
range_without_total: "%{from}-%{to} eventos"
de: &de
+ use_direct_file_attachment_links_in_the_documents: Verwenden Sie direkte Dateianhang-Links in den Dokumenten
click_here_to_send_a_reset_password_email_html: 'Klicken Sie hier, um eine E-Mail zum Zurücksetzen des Passworts zu senden.'
enabled: Aktiviert
disabled: Deaktiviert
@@ -5156,6 +5172,8 @@ de: &de
four_days: 4 Tage
eight_days: 8 Tage
fifteen_days: 15 Tage
+ twenty_one_days: 21 Tage
+ thirty_days: 30 Tage
free: Kostenlos
unlimited_documents_storage: Unbegrenzter Dokumentenspeicher
users_management: Benutzerverwaltung
diff --git a/lib/account_configs.rb b/lib/account_configs.rb
index 111320f8..06fec78f 100644
--- a/lib/account_configs.rb
+++ b/lib/account_configs.rb
@@ -15,7 +15,9 @@ module AccountConfigs
'six_days' => '6 days',
'seven_days' => '7 days',
'eight_days' => '8 days',
- 'fifteen_days' => '15 days'
+ 'fifteen_days' => '15 days',
+ 'twenty_one_days' => '21 days',
+ 'thirty_days' => '30 days'
}.freeze
module_function
diff --git a/lib/submissions/create_from_submitters.rb b/lib/submissions/create_from_submitters.rb
index 29aa37e8..0ae3b09b 100644
--- a/lib/submissions/create_from_submitters.rb
+++ b/lib/submissions/create_from_submitters.rb
@@ -145,7 +145,7 @@ module Submissions
submitters_attrs.any? { |e| e[:completed].present? } || !with_template || submission.variables.present?
submission.template_fields = template_fields
submission.template_schema = submission.template.schema if submission.template_schema.blank?
- submission.variables_schema = submission.template.variables_schema if submission.template_id &&
+ submission.variables_schema = submission.template.variables_schema if submission.template &&
submission.variables_schema.blank?
end
diff --git a/lib/submissions/generate_audit_trail.rb b/lib/submissions/generate_audit_trail.rb
index 6413c68b..b63f3c6f 100644
--- a/lib/submissions/generate_audit_trail.rb
+++ b/lib/submissions/generate_audit_trail.rb
@@ -329,7 +329,7 @@ module Submissions
submitter_field_counters[field['type']] += 1
next if field['submitter_uuid'] != submitter.uuid
- next if field['type'] == 'heading'
+ next if field['type'] == 'heading' || field['type'] == 'strikethrough'
next if !with_audit_values && !field['type'].in?(%w[signature initials])
next if skip_grouped_field_uuids[field['uuid']]
diff --git a/lib/submissions/generate_result_attachments.rb b/lib/submissions/generate_result_attachments.rb
index 4e060770..54eb694f 100644
--- a/lib/submissions/generate_result_attachments.rb
+++ b/lib/submissions/generate_result_attachments.rb
@@ -206,15 +206,16 @@ module Submissions
submission = submitter.submission
- return pdfs_index if submission.template_fields.blank?
-
with_headings = find_last_submitter(submission, submitter:).blank? if with_headings.nil?
locale = submitter.metadata.fetch('lang', account.locale)
- submission.template_fields.each do |field|
- next if field['type'] == 'heading' && !with_headings
- next if field['submitter_uuid'] != submitter.uuid && field['type'] != 'heading'
+ (submission.template_fields || submission.template.fields).each do |field|
+ next if !with_headings &&
+ (field['type'] == 'heading' || (field['type'] == 'strikethrough' && field['conditions'].blank?))
+
+ next if field['submitter_uuid'] != submitter.uuid && field['type'] != 'heading' &&
+ (field['type'] != 'strikethrough' || field['conditions'].present?)
field.fetch('areas', []).each do |area|
pdf = pdfs_index[area['attachment_uuid']]
@@ -258,6 +259,7 @@ module Submissions
value = submitter.values[field['uuid']]
value = field['default_value'] if field['type'] == 'heading'
+ value = field['default_value'] if field['type'] == 'strikethrough' && value.nil? && field['conditions'].blank?
text_align = field.dig('preferences', 'align').to_s.to_sym.presence ||
(value.to_s.match?(RTL_REGEXP) ? :right : :left)
@@ -448,8 +450,7 @@ module Submissions
cv.image(PdfIcons.paperclip_io, at: [0, 0], width: box.content_width)
end
- acc << HexaPDF::Layout::TextFragment.create("#{attachment.filename}\n", font:,
- font_size:)
+ acc << HexaPDF::Layout::TextFragment.create("#{attachment.filename}\n", font:, font_size:)
end
lines = layouter.fit(items, area['w'] * width, height).lines
@@ -567,6 +568,43 @@ module Submissions
cell_layouter.fit([text], cell_width, [line_height, area['h'] * height].max)
.draw(canvas, x, height - (area['y'] * height))
end
+ when 'strikethrough'
+ scale = 1000.0 / width
+
+ line_width = 6.0 / scale
+ area_height = area['h'] * height
+
+ if area_height * scale < 40.0
+ canvas.tap do |c|
+ c.stroke_color(field.dig('preferences', 'color').presence || 'red')
+ c.line_width(line_width)
+ c.line(width * area['x'],
+ height - (height * area['y']) - (area_height / 2),
+ (width * area['x']) + (width * area['w']),
+ height - (height * area['y']) - (area_height / 2))
+ c.stroke
+ end
+ else
+ canvas.tap do |c|
+ c.stroke_color(field.dig('preferences', 'color').presence || 'red')
+ c.line_width(line_width)
+ c.line((width * area['x']) + (line_width / 2),
+ height - (height * area['y']) - (line_width / 2),
+ (width * area['x']) + (width * area['w']) - (line_width / 2),
+ height - (height * area['y']) - area_height + (line_width / 2))
+ c.stroke
+ end
+
+ canvas.tap do |c|
+ c.stroke_color(field.dig('preferences', 'color').presence || 'red')
+ c.line_width(line_width)
+ c.line((width * area['x']) + (line_width / 2),
+ height - (height * area['y']) - area_height + (line_width / 2),
+ (width * area['x']) + (width * area['w']) - (line_width / 2),
+ height - (height * area['y']) - (line_width / 2))
+ c.stroke
+ end
+ end
else
if field['type'] == 'date'
value = TimeUtils.format_date_string(value, field.dig('preferences', 'format'), locale)
diff --git a/lib/submitters/submit_values.rb b/lib/submitters/submit_values.rb
index 63b1d839..613fca55 100644
--- a/lib/submitters/submit_values.rb
+++ b/lib/submitters/submit_values.rb
@@ -6,7 +6,7 @@ module Submitters
RequiredFieldError = Class.new(StandardError)
VARIABLE_REGEXP = /\{\{?(\w+)\}\}?/
- NONEDITABLE_FIELD_TYPES = %w[stamp heading].freeze
+ NONEDITABLE_FIELD_TYPES = %w[stamp heading strikethrough].freeze
STRFTIME_MAP = {
'hour' => '%-k',
@@ -189,8 +189,6 @@ module Submitters
next if formula.blank?
- formula = normalize_formula(formula, submitter.submission)
-
submission_values ||=
if submitter.submission.template_submitters.size > 1
merge_submitters_values(submitter)
@@ -198,20 +196,26 @@ module Submitters
submitter.values
end
+ formula = normalize_formula(formula, submitter.submission, submission_values:)
+
acc[field['uuid']] = calculate_formula_value(formula, submission_values.merge(acc.compact_blank))
end
computed_values.compact_blank
end
- def normalize_formula(formula, submission, depth = 0)
+ def normalize_formula(formula, submission, depth: 0, submission_values: nil)
raise ValidationError, 'Formula infinite loop' if depth > 10
formula.gsub(/{{(.*?)}}/) do |match|
uuid = Regexp.last_match(1)
if (nested_formula = submission.fields_uuid_index.dig(uuid, 'preferences', 'formula').presence)
- "(#{normalize_formula(nested_formula, submission, depth + 1)})"
+ if check_field_conditions(submission_values, submission.fields_uuid_index[uuid], submission.fields_uuid_index)
+ "(#{normalize_formula(nested_formula, submission, depth: depth + 1, submission_values:)})"
+ else
+ '0'
+ end
else
match
end
diff --git a/lib/time_utils.rb b/lib/time_utils.rb
index 292b67bb..c1c0d07e 100644
--- a/lib/time_utils.rb
+++ b/lib/time_utils.rb
@@ -57,9 +57,9 @@ module TimeUtils
format ||= locale.to_s.ends_with?('US') ? DEFAULT_DATE_FORMAT_US : DEFAULT_DATE_FORMAT
- i18n_format = format.sub(/D+/, DAY_FORMATS[format[/D+/]])
- .sub(/M+/, MONTH_FORMATS[format[/M+/]])
- .sub(/Y+/, YEAR_FORMATS[format[/Y+/]])
+ i18n_format = format.sub(/D+/) { DAY_FORMATS[format[/D+/]] }
+ .sub(/M+/) { MONTH_FORMATS[format[/M+/]] }
+ .sub(/Y+/) { YEAR_FORMATS[format[/Y+/]] }
I18n.l(date, format: i18n_format, locale:)
rescue Date::Error
diff --git a/package.json b/package.json
index 55e29502..4b664b19 100644
--- a/package.json
+++ b/package.json
@@ -38,7 +38,7 @@
"shakapacker": "8.0.0",
"signature_pad": "^4.1.5",
"snarkdown": "^2.0.0",
- "tailwindcss": "^3.3.2",
+ "tailwindcss": "^3.4.17",
"terser-webpack-plugin": "5.3.8",
"uuid": "^9.0.0",
"vue": "^3.3.2",
diff --git a/spec/system/template_spec.rb b/spec/system/template_spec.rb
index d343283e..83aa0f8d 100644
--- a/spec/system/template_spec.rb
+++ b/spec/system/template_spec.rb
@@ -78,7 +78,7 @@ RSpec.describe 'Template' do
within '#modal' do
fill_in 'template[name]', with: 'New Template Name'
- click_link 'Change Folder'
+ find('label', text: 'Change Folder').click
fill_in 'folder_name', with: 'New Folder Name'
expect do
@@ -101,7 +101,7 @@ RSpec.describe 'Template' do
within '#modal' do
template_folder.reload
fill_in 'template[name]', with: 'New Template Name'
- click_link 'Change Folder'
+ find('label', text: 'Change Folder').click
end
within '.autocomplete' do
diff --git a/yarn.lock b/yarn.lock
index 08dea370..2faf9648 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1239,6 +1239,18 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
+"@isaacs/cliui@^8.0.2":
+ version "8.0.2"
+ resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550"
+ integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==
+ dependencies:
+ string-width "^5.1.2"
+ string-width-cjs "npm:string-width@^4.2.0"
+ strip-ansi "^7.0.1"
+ strip-ansi-cjs "npm:strip-ansi@^6.0.1"
+ wrap-ansi "^8.1.0"
+ wrap-ansi-cjs "npm:wrap-ansi@^7.0.0"
+
"@jest/schemas@^29.4.3":
version "29.4.3"
resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.4.3.tgz#39cf1b8469afc40b6f5a2baaa146e332c4151788"
@@ -1427,6 +1439,11 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
+"@pkgjs/parseargs@^0.11.0":
+ version "0.11.0"
+ resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
+ integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
+
"@polka/url@^1.0.0-next.20":
version "1.0.0-next.21"
resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1"
@@ -1965,6 +1982,11 @@ ansi-regex@^5.0.1:
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
+ansi-regex@^6.0.1:
+ version "6.2.2"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.2.2.tgz#60216eea464d864597ce2832000738a0589650c1"
+ integrity sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==
+
ansi-styles@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
@@ -1972,13 +1994,18 @@ ansi-styles@^3.2.1:
dependencies:
color-convert "^1.9.0"
-ansi-styles@^4.1.0:
+ansi-styles@^4.0.0, ansi-styles@^4.1.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
dependencies:
color-convert "^2.0.1"
+ansi-styles@^6.1.0:
+ version "6.2.3"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.3.tgz#c044d5dcc521a076413472597a1acb1f103c4041"
+ integrity sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==
+
any-promise@^1.0.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
@@ -2208,7 +2235,14 @@ brace-expansion@^1.1.7:
balanced-match "^1.0.0"
concat-map "0.0.1"
-braces@^3.0.2, braces@~3.0.2:
+brace-expansion@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.2.tgz#54fc53237a613d854c7bd37463aad17df87214e7"
+ integrity sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==
+ dependencies:
+ balanced-match "^1.0.0"
+
+braces@^3.0.2, braces@^3.0.3, braces@~3.0.2:
version "3.0.3"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
@@ -2322,6 +2356,21 @@ chalk@^4.0, chalk@^4.0.0, chalk@^4.1.0:
optionalDependencies:
fsevents "~2.3.2"
+chokidar@^3.6.0:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b"
+ integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==
+ dependencies:
+ anymatch "~3.1.2"
+ braces "~3.0.2"
+ glob-parent "~5.1.2"
+ is-binary-path "~2.1.0"
+ is-glob "~4.0.1"
+ normalize-path "~3.0.0"
+ readdirp "~3.6.0"
+ optionalDependencies:
+ fsevents "~2.3.2"
+
chrome-trace-event@^1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac"
@@ -2547,6 +2596,15 @@ cross-spawn@^7.0.2, cross-spawn@^7.0.3:
shebang-command "^2.0.0"
which "^2.0.1"
+cross-spawn@^7.0.6:
+ version "7.0.6"
+ resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"
+ integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==
+ dependencies:
+ path-key "^3.1.0"
+ shebang-command "^2.0.0"
+ which "^2.0.1"
+
css-declaration-sorter@^6.3.1:
version "6.4.0"
resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.4.0.tgz#630618adc21724484b3e9505bce812def44000ad"
@@ -2875,6 +2933,11 @@ duplexer@^0.1.2:
resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6"
integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==
+eastasianwidth@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb"
+ integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==
+
ee-first@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
@@ -2885,6 +2948,16 @@ electron-to-chromium@^1.5.4:
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz#1abf0410c5344b2b829b7247e031f02810d442e6"
integrity sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==
+emoji-regex@^8.0.0:
+ version "8.0.0"
+ resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
+ integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
+
+emoji-regex@^9.2.2:
+ version "9.2.2"
+ resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72"
+ integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
+
encodeurl@~1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
@@ -3304,10 +3377,10 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
-fast-glob@^3.2.12:
- version "3.2.12"
- resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80"
- integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==
+fast-glob@^3.3.0:
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129"
+ integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==
dependencies:
"@nodelib/fs.stat" "^2.0.2"
"@nodelib/fs.walk" "^1.2.3"
@@ -3315,16 +3388,16 @@ fast-glob@^3.2.12:
merge2 "^1.3.0"
micromatch "^4.0.4"
-fast-glob@^3.3.0:
- version "3.3.2"
- resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129"
- integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==
+fast-glob@^3.3.2:
+ version "3.3.3"
+ resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818"
+ integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==
dependencies:
"@nodelib/fs.stat" "^2.0.2"
"@nodelib/fs.walk" "^1.2.3"
glob-parent "^5.1.2"
merge2 "^1.3.0"
- micromatch "^4.0.4"
+ micromatch "^4.0.8"
fast-json-stable-stringify@^2.0.0:
version "2.1.0"
@@ -3449,6 +3522,14 @@ for-each@^0.3.3:
dependencies:
is-callable "^1.1.3"
+foreground-child@^3.1.0:
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.1.tgz#32e8e9ed1b68a3497befb9ac2b6adf92a638576f"
+ integrity sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==
+ dependencies:
+ cross-spawn "^7.0.6"
+ signal-exit "^4.0.1"
+
form-data@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.1.tgz#ba1076daaaa5bfd7e99c1a6cb02aa0a5cff90d48"
@@ -3498,6 +3579,11 @@ function-bind@^1.1.1:
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
+function-bind@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
+ integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
+
function.prototype.name@^1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621"
@@ -3572,6 +3658,18 @@ glob@7.1.6:
once "^1.3.0"
path-is-absolute "^1.0.0"
+glob@^10.3.10:
+ version "10.4.5"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956"
+ integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==
+ dependencies:
+ foreground-child "^3.1.0"
+ jackspeak "^3.1.2"
+ minimatch "^9.0.4"
+ minipass "^7.1.2"
+ package-json-from-dist "^1.0.0"
+ path-scurry "^1.11.1"
+
glob@^7.1.3:
version "7.2.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
@@ -3683,6 +3781,13 @@ hash-sum@^2.0.0:
resolved "https://registry.yarnpkg.com/hash-sum/-/hash-sum-2.0.0.tgz#81d01bb5de8ea4a214ad5d6ead1b523460b0b45a"
integrity sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==
+hasown@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
+ integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
+ dependencies:
+ function-bind "^1.1.2"
+
hpack.js@^2.1.6:
version "2.1.6"
resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2"
@@ -3904,6 +4009,13 @@ is-core-module@^2.11.0:
dependencies:
has "^1.0.3"
+is-core-module@^2.16.0:
+ version "2.16.1"
+ resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4"
+ integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==
+ dependencies:
+ hasown "^2.0.2"
+
is-date-object@^1.0.1:
version "1.0.5"
resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f"
@@ -3921,6 +4033,11 @@ is-extglob@^2.1.1:
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
+is-fullwidth-code-point@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
+ integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
+
is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
version "4.0.3"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
@@ -4036,6 +4153,15 @@ isobject@^3.0.1:
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==
+jackspeak@^3.1.2:
+ version "3.4.3"
+ resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a"
+ integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==
+ dependencies:
+ "@isaacs/cliui" "^8.0.2"
+ optionalDependencies:
+ "@pkgjs/parseargs" "^0.11.0"
+
javascript-natural-sort@^0.7.1:
version "0.7.1"
resolved "https://registry.yarnpkg.com/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz#f9e2303d4507f6d74355a73664d1440fb5a0ef59"
@@ -4082,6 +4208,11 @@ jiti@^1.21.0:
resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.0.tgz#7c97f8fe045724e136a397f7340475244156105d"
integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==
+jiti@^1.21.6:
+ version "1.21.7"
+ resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.7.tgz#9dd81043424a3d28458b193d965f0d18a2300ba9"
+ integrity sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==
+
js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
@@ -4177,6 +4308,11 @@ lilconfig@^2.0.5, lilconfig@^2.1.0:
resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52"
integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==
+lilconfig@^3.0.0, lilconfig@^3.1.3:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.3.tgz#a1bcfd6257f9585bf5ae14ceeebb7b559025e4c4"
+ integrity sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==
+
lines-and-columns@^1.1.6:
version "1.2.4"
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
@@ -4248,6 +4384,11 @@ lodash@^4.17.20, lodash@^4.17.21:
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
+lru-cache@^10.2.0:
+ version "10.4.3"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119"
+ integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==
+
lru-cache@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
@@ -4346,6 +4487,14 @@ micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5:
braces "^3.0.2"
picomatch "^2.3.1"
+micromatch@^4.0.8:
+ version "4.0.8"
+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202"
+ integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==
+ dependencies:
+ braces "^3.0.3"
+ picomatch "^2.3.1"
+
mime-db@1.52.0, "mime-db@>= 1.43.0 < 2":
version "1.52.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
@@ -4387,11 +4536,23 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
dependencies:
brace-expansion "^1.1.7"
+minimatch@^9.0.4:
+ version "9.0.5"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5"
+ integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==
+ dependencies:
+ brace-expansion "^2.0.1"
+
minimist@^1.2.0, minimist@^1.2.6:
version "1.2.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
+"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2:
+ version "7.1.2"
+ resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707"
+ integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==
+
mrmime@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-1.0.1.tgz#5f90c825fad4bdd41dc914eff5d1a8cfdaf24f27"
@@ -4429,6 +4590,11 @@ mz@^2.7.0:
object-assign "^4.0.1"
thenify-all "^1.0.0"
+nanoid@^3.3.11:
+ version "3.3.11"
+ resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b"
+ integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==
+
nanoid@^3.3.6:
version "3.3.6"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c"
@@ -4625,6 +4791,11 @@ p-try@^2.0.0:
resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
+package-json-from-dist@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505"
+ integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==
+
parent-module@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
@@ -4672,6 +4843,14 @@ path-parse@^1.0.7:
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
+path-scurry@^1.11.1:
+ version "1.11.1"
+ resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2"
+ integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==
+ dependencies:
+ lru-cache "^10.2.0"
+ minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
+
path-to-regexp@0.1.7:
version "0.1.7"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
@@ -4789,6 +4968,14 @@ postcss-load-config@^4.0.1:
lilconfig "^2.0.5"
yaml "^2.1.1"
+postcss-load-config@^4.0.2:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-4.0.2.tgz#7159dcf626118d33e299f485d6afe4aff7c4a3e3"
+ integrity sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==
+ dependencies:
+ lilconfig "^3.0.0"
+ yaml "^2.3.4"
+
postcss-loader@^7.3.0:
version "7.3.0"
resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-7.3.0.tgz#05991c1e490d8ff86ef18358d87db3b5b2dcb5f5"
@@ -4884,6 +5071,13 @@ postcss-nested@^6.0.1:
dependencies:
postcss-selector-parser "^6.0.11"
+postcss-nested@^6.2.0:
+ version "6.2.0"
+ resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-6.2.0.tgz#4c2d22ab5f20b9cb61e2c5c5915950784d068131"
+ integrity sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==
+ dependencies:
+ postcss-selector-parser "^6.1.1"
+
postcss-normalize-charset@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-6.0.0.tgz#36cc12457259064969fb96f84df491652a4b0975"
@@ -4977,6 +5171,14 @@ postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.0.2, postcss-selecto
cssesc "^3.0.0"
util-deprecate "^1.0.2"
+postcss-selector-parser@^6.1.1, postcss-selector-parser@^6.1.2:
+ version "6.1.2"
+ resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz#27ecb41fb0e3b6ba7a1ec84fff347f734c7929de"
+ integrity sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==
+ dependencies:
+ cssesc "^3.0.0"
+ util-deprecate "^1.0.2"
+
postcss-svgo@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-6.0.0.tgz#7b18742d38d4505a0455bbe70d52b49f00eaf69d"
@@ -5015,6 +5217,15 @@ postcss@^8.4.14:
picocolors "^1.1.1"
source-map-js "^1.2.1"
+postcss@^8.4.47:
+ version "8.5.6"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.6.tgz#2825006615a619b4f62a9e7426cc120b349a8f3c"
+ integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==
+ dependencies:
+ nanoid "^3.3.11"
+ picocolors "^1.1.1"
+ source-map-js "^1.2.1"
+
prelude-ls@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
@@ -5233,6 +5444,15 @@ resolve@^1.1.7, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
+resolve@^1.22.8:
+ version "1.22.10"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39"
+ integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==
+ dependencies:
+ is-core-module "^2.16.0"
+ path-parse "^1.0.7"
+ supports-preserve-symlinks-flag "^1.0.0"
+
retry@^0.13.1:
version "0.13.1"
resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658"
@@ -5473,6 +5693,11 @@ signal-exit@^3.0.2, signal-exit@^3.0.3:
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
+signal-exit@^4.0.1:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04"
+ integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==
+
signature_pad@^4.1.4:
version "4.2.0"
resolved "https://registry.yarnpkg.com/signature_pad/-/signature_pad-4.2.0.tgz#7513cee8cb8afd6594d871c61cf4d61420601422"
@@ -5572,6 +5797,33 @@ statuses@2.0.1:
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==
+"string-width-cjs@npm:string-width@^4.2.0":
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
+ integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
+ dependencies:
+ emoji-regex "^8.0.0"
+ is-fullwidth-code-point "^3.0.0"
+ strip-ansi "^6.0.1"
+
+string-width@^4.1.0:
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
+ integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
+ dependencies:
+ emoji-regex "^8.0.0"
+ is-fullwidth-code-point "^3.0.0"
+ strip-ansi "^6.0.1"
+
+string-width@^5.0.1, string-width@^5.1.2:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794"
+ integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==
+ dependencies:
+ eastasianwidth "^0.2.0"
+ emoji-regex "^9.2.2"
+ strip-ansi "^7.0.1"
+
string.prototype.trim@^1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz#a68352740859f6893f14ce3ef1bb3037f7a90533"
@@ -5613,13 +5865,27 @@ string_decoder@~1.1.1:
dependencies:
safe-buffer "~5.1.0"
-strip-ansi@^6.0.1:
+"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
+ integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
+ dependencies:
+ ansi-regex "^5.0.1"
+
+strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"
+strip-ansi@^7.0.1:
+ version "7.1.2"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.2.tgz#132875abde678c7ea8d691533f2e7e22bb744dba"
+ integrity sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==
+ dependencies:
+ ansi-regex "^6.0.1"
+
strip-bom@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
@@ -5661,6 +5927,19 @@ sucrase@^3.32.0:
pirates "^4.0.1"
ts-interface-checker "^0.1.9"
+sucrase@^3.35.0:
+ version "3.35.0"
+ resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.35.0.tgz#57f17a3d7e19b36d8995f06679d121be914ae263"
+ integrity sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==
+ dependencies:
+ "@jridgewell/gen-mapping" "^0.3.2"
+ commander "^4.0.0"
+ glob "^10.3.10"
+ lines-and-columns "^1.1.6"
+ mz "^2.7.0"
+ pirates "^4.0.1"
+ ts-interface-checker "^0.1.9"
+
supports-color@^5.3.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
@@ -5727,34 +6006,33 @@ tailwindcss@^3.1:
resolve "^1.22.2"
sucrase "^3.32.0"
-tailwindcss@^3.3.2:
- version "3.3.2"
- resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.3.2.tgz#2f9e35d715fdf0bbf674d90147a0684d7054a2d3"
- integrity sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w==
+tailwindcss@^3.4.17:
+ version "3.4.17"
+ resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.17.tgz#ae8406c0f96696a631c790768ff319d46d5e5a63"
+ integrity sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==
dependencies:
"@alloc/quick-lru" "^5.2.0"
arg "^5.0.2"
- chokidar "^3.5.3"
+ chokidar "^3.6.0"
didyoumean "^1.2.2"
dlv "^1.1.3"
- fast-glob "^3.2.12"
+ fast-glob "^3.3.2"
glob-parent "^6.0.2"
is-glob "^4.0.3"
- jiti "^1.18.2"
- lilconfig "^2.1.0"
- micromatch "^4.0.5"
+ jiti "^1.21.6"
+ lilconfig "^3.1.3"
+ micromatch "^4.0.8"
normalize-path "^3.0.0"
object-hash "^3.0.0"
- picocolors "^1.0.0"
- postcss "^8.4.23"
+ picocolors "^1.1.1"
+ postcss "^8.4.47"
postcss-import "^15.1.0"
postcss-js "^4.0.1"
- postcss-load-config "^4.0.1"
- postcss-nested "^6.0.1"
- postcss-selector-parser "^6.0.11"
- postcss-value-parser "^4.2.0"
- resolve "^1.22.2"
- sucrase "^3.32.0"
+ postcss-load-config "^4.0.2"
+ postcss-nested "^6.2.0"
+ postcss-selector-parser "^6.1.2"
+ resolve "^1.22.8"
+ sucrase "^3.35.0"
tapable@^2.0, tapable@^2.1.1, tapable@^2.2.0:
version "2.2.1"
@@ -6258,6 +6536,24 @@ word-wrap@^1.2.3:
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34"
integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==
+"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
+ integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
+ dependencies:
+ ansi-styles "^4.0.0"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+
+wrap-ansi@^8.1.0:
+ version "8.1.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
+ integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==
+ dependencies:
+ ansi-styles "^6.1.0"
+ string-width "^5.0.1"
+ strip-ansi "^7.0.1"
+
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
@@ -6298,6 +6594,11 @@ yaml@^2.1.1:
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.1.tgz#02fe0975d23cd441242aa7204e09fc28ac2ac33b"
integrity sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==
+yaml@^2.3.4:
+ version "2.8.1"
+ resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.8.1.tgz#1870aa02b631f7e8328b93f8bc574fac5d6c4d79"
+ integrity sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==
+
yocto-queue@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"