diff --git a/.travis.yml b/.travis.yml index 95291a551..c04c0e859 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ env: - - DOCKER_COMPOSE_VERSION=1.23.2 - + - DOCKER_COMPOSE_VERSION=v2.22.0 +dist: jammy sudo: required language: ruby addons: @@ -10,9 +10,9 @@ services: - docker before_install: - sudo rm /usr/local/bin/docker-compose - - curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose + - curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-linux-x86_64 > docker-compose - chmod +x docker-compose - sudo mv docker-compose /usr/local/bin - - make docker + - make docker-ci script: - make tests-ci diff --git a/Makefile b/Makefile index ea90052ec..246d213e3 100644 --- a/Makefile +++ b/Makefile @@ -24,6 +24,9 @@ heroku: docker: @docker-compose build +docker-ci: + @docker-compose --progress plain build web + docker-production: @docker-compose -f docker-compose.production.yml build --build-arg BUILD_TIMESTAMP=$(BUILD_TIMESTAMP) @@ -81,10 +84,17 @@ integration-tests: @$(MAKE) rails cmd="bundle exec cucumber" tests-ci: - @docker-compose run --rm web bash -c "bundle install && yarn install" - @docker-compose up -d webpack - @docker-compose ps - @docker-compose run -e ENABLE_EMAIL_CONFIRMATIONS=false -e MAIL_FROM=MAIL_FROM -e MAIL_REPLYTO=MAIL_REPLYTO -e RAILS_ENV=test -e MAIL_SERVER_URL=localhost:3000 -e ENABLE_RECAPTCHA=false -e ENABLE_USER_CONFIRMATION=false -e ENABLE_USER_REGISTRATION=true -e CORE_API_RATE_LIMIT=1000000 --rm web bash -c "rake db:create && rake db:migrate && yarn install && bundle exec rspec" + @docker-compose run --rm web bash -c "bundle install" + @docker-compose run -e ENABLE_EMAIL_CONFIRMATIONS=false \ + -e MAIL_FROM=MAIL_FROM \ + -e MAIL_REPLYTO=MAIL_REPLYTO \ + -e RAILS_ENV=test \ + -e MAIL_SERVER_URL=localhost:3000 \ + -e ENABLE_RECAPTCHA=false \ + -e ENABLE_USER_CONFIRMATION=false \ + -e ENABLE_USER_REGISTRATION=true \ + -e CORE_API_RATE_LIMIT=1000000 \ + --rm web bash -c "rake db:create && rake db:migrate && bundle exec rspec ./spec/requests/api/" console: @$(MAKE) rails cmd="rails console" diff --git a/VERSION b/VERSION index eb6c80e2b..0bb3ab4d7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.29.0.1 +1.29.1.1 diff --git a/app/assets/javascripts/projects/index.js b/app/assets/javascripts/projects/index.js index ffb96ab65..7f063a0f1 100644 --- a/app/assets/javascripts/projects/index.js +++ b/app/assets/javascripts/projects/index.js @@ -430,7 +430,7 @@ var ProjectsIndex = (function() { view_mode: $('.projects-index').data('view-mode'), sort: projectsCurrentSort, search: projectsViewSearch, - members: membersFilter, + members: membersFilter && membersFilter.map(m => m.value), created_on_from: createdOnFromFilter, created_on_to: createdOnToFilter, folders_search: lookInsideFolders, @@ -549,6 +549,8 @@ var ProjectsIndex = (function() { var datePicker = $field.data('DateTimePicker'); if (datePicker && datePicker.date()) { return datePicker.date()._d.toUTCString(); + } else if ($field.val()) { + return moment($field.val(), $field.data('dateFormat'))._d.toUTCString(); } return null; } @@ -565,8 +567,8 @@ var ProjectsIndex = (function() { let $textFilter = $('#textSearchFilterInput', $projectsFilter); function getFilterValues() { - createdOnFromFilter = selectDate($createdOnFromFilter) || $createdOnFromFilter.val(); - createdOnToFilter = selectDate($createdOnToFilter) || $createdOnToFilter.val(); + createdOnFromFilter = selectDate($createdOnFromFilter); + createdOnToFilter = selectDate($createdOnToFilter); membersFilter = dropdownSelector.getData($('.members-filter')); lookInsideFolders = $foldersCB.prop('checked') || ''; archivedOnFromFilter = selectDate($archivedOnFromFilter) || $archivedOnFromFilter.val(); diff --git a/app/assets/stylesheets/protocols/index.scss b/app/assets/stylesheets/protocols/index.scss index 662fa0065..7bb510962 100644 --- a/app/assets/stylesheets/protocols/index.scss +++ b/app/assets/stylesheets/protocols/index.scss @@ -20,7 +20,7 @@ width: 100%; .dataTables_scrollHead { - overflow: visible !important; + flex-shrink: 0; thead { .sci-checkbox-container { diff --git a/app/assets/stylesheets/tailwind/inputs.css b/app/assets/stylesheets/tailwind/inputs.css index 963aa94bd..805ce15b1 100644 --- a/app/assets/stylesheets/tailwind/inputs.css +++ b/app/assets/stylesheets/tailwind/inputs.css @@ -1,7 +1,7 @@ @layer components { .sci-label { - @apply text-sm font-medium text-sn-grey; + @apply text-sm font-medium text-sn-dark-grey; } .sci-input-container-v2 { diff --git a/app/controllers/api/v1/inventory_status_items_controller.rb b/app/controllers/api/v1/inventory_status_items_controller.rb index 09d4cb032..45a519270 100644 --- a/app/controllers/api/v1/inventory_status_items_controller.rb +++ b/app/controllers/api/v1/inventory_status_items_controller.rb @@ -12,7 +12,6 @@ module Api timestamps_filter( @inventory_column.repository_status_items ) - .repository_status_items .page(params.dig(:page, :number)) .per(params.dig(:page, :size)) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 8242d6be2..44e1dff6f 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -137,14 +137,13 @@ module ApplicationHelper # and outputs a popover with user information def smart_annotation_filter_users(text, team, base64_encoded_imgs: false) sa_user = /\[\@(.*?)~([0-9a-zA-Z]+)\]/ - new_text = text.gsub(sa_user) do |el| + text.gsub(sa_user) do |el| match = el.match(sa_user) user = User.find_by_id(match[2].base62_decode) next unless user popover_for_user_name(user, team, false, false, base64_encoded_imgs) end - sanitize_input(new_text) end # Generate smart annotation link for one user object diff --git a/app/javascript/vue/protocol/container.vue b/app/javascript/vue/protocol/container.vue index 3314ee999..aacbaa6ea 100644 --- a/app/javascript/vue/protocol/container.vue +++ b/app/javascript/vue/protocol/container.vue @@ -210,6 +210,14 @@ @publish="publishProtocol" @cancel="closePublishModal" /> + @@ -221,6 +229,8 @@ import Tinymce from '../shared/tinymce.vue' import ReorderableItemsModal from '../shared/reorderable_items_modal.vue' import PublishProtocol from './modals/publish_protocol.vue' + import clipboardPasteModal from '../shared/content/attachments/clipboard_paste_modal.vue' + import AssetPasteMixin from '../shared/content/attachments/mixins/paste.js' import UtilsMixin from '../mixins/utils.js' import stackableHeadersMixin from '../mixins/stackableHeadersMixin'; @@ -234,8 +244,8 @@ required: true } }, - components: { Step, InlineEdit, ProtocolOptions, Tinymce, ReorderableItemsModal, ProtocolMetadata, PublishProtocol}, - mixins: [UtilsMixin, stackableHeadersMixin, moduleNameObserver], + components: { Step, InlineEdit, ProtocolOptions, Tinymce, ReorderableItemsModal, ProtocolMetadata, PublishProtocol, clipboardPasteModal}, + mixins: [UtilsMixin, stackableHeadersMixin, moduleNameObserver, AssetPasteMixin], computed: { inRepository() { return this.protocol.attributes.in_repository @@ -245,7 +255,7 @@ }, urls() { return this.protocol.attributes.urls || {} - } + }, }, data() { return { @@ -433,6 +443,16 @@ $('.my_module-name .view-mode').trigger('click'); $('.my_module-name .input-field').focus(); }, 300) + }, + uploadFilesToStep(file, stepId) { + this.$children.find(child => child.step?.id == stepId).uploadFiles(file); + }, + firstObjectInViewport() { + let step = $('.step-container:not(.locked)').toArray().find(element => { + const { top, bottom } = element.getBoundingClientRect() + return bottom > 0 && top < window.innerHeight + }) + return step ? step.dataset.id : null } } } diff --git a/app/javascript/vue/protocol/step.vue b/app/javascript/vue/protocol/step.vue index 52f00dfa4..577da8d84 100644 --- a/app/javascript/vue/protocol/step.vue +++ b/app/javascript/vue/protocol/step.vue @@ -4,7 +4,8 @@ @drop.prevent="dropFile" @dragenter.prevent="dragEnter($event)" @dragover.prevent - :class="{ 'draging-file': dragingFile, 'editing-name': editingName }" + :data-id="step.id" + :class="{ 'draging-file': dragingFile, 'editing-name': editingName, 'locked': !urls.update_url }" >
{{ i18n.t('protocols.steps.drop_message', { position: step.attributes.position + 1 }) }} @@ -134,12 +135,6 @@
- { diff --git a/app/javascript/vue/repository_item_sidebar/repository_values/RepositoryTextValue.vue b/app/javascript/vue/repository_item_sidebar/repository_values/RepositoryTextValue.vue index 8c63fb785..f370c2e5a 100644 --- a/app/javascript/vue/repository_item_sidebar/repository_values/RepositoryTextValue.vue +++ b/app/javascript/vue/repository_item_sidebar/repository_values/RepositoryTextValue.vue @@ -46,8 +46,10 @@ export default { }, mounted() { this.$nextTick(() => { - const textHeight = this.$refs.textRef.scrollHeight - this.expandable = textHeight > 60 // 60px + if (this.$refs.textRef) { + const textHeight = this.$refs.textRef.scrollHeight + this.expandable = textHeight > 60 // 60px + } }) }, } diff --git a/app/javascript/vue/results/result.vue b/app/javascript/vue/results/result.vue index 655bd3eac..2b51d941a 100644 --- a/app/javascript/vue/results/result.vue +++ b/app/javascript/vue/results/result.vue @@ -3,7 +3,8 @@ @drop.prevent="dropFile" @dragenter.prevent="dragEnter($event)" @dragover.prevent - :class="{ 'bg-sn-super-light-blue': dragingFile, 'bg-white': !dragingFile }" + :data-id="result.id" + :class="{ 'bg-sn-super-light-blue': dragingFile, 'bg-white': !dragingFile, 'locked': locked }" >
+ @@ -43,10 +51,13 @@ import stackableHeadersMixin from '../mixins/stackableHeadersMixin'; import moduleNameObserver from '../mixins/moduleNameObserver'; + import clipboardPasteModal from '../shared/content/attachments/clipboard_paste_modal.vue' + import AssetPasteMixin from '../shared/content/attachments/mixins/paste.js' + export default { name: 'Results', - components: { ResultsToolbar, Result }, - mixins: [stackableHeadersMixin, moduleNameObserver], + components: { ResultsToolbar, Result, clipboardPasteModal }, + mixins: [stackableHeadersMixin, moduleNameObserver, AssetPasteMixin], props: { url: { type: String, required: true }, canCreate: { type: String, required: true }, @@ -136,6 +147,16 @@ }, dragEnter(id) { this.activeDragResult = id; + }, + uploadFilesToResult(file, resultId) { + this.$children.find(child => child.result?.id == resultId).uploadFiles(file); + }, + firstObjectInViewport() { + let result = $('.result-wrapper:not(.locked)').toArray().find(element => { + const { top, bottom } = element.getBoundingClientRect() + return bottom > 0 && top < window.innerHeight + }) + return result ? result.dataset.id : null } } } diff --git a/app/javascript/vue/shared/content/attachments/clipboard_paste_modal.vue b/app/javascript/vue/shared/content/attachments/clipboard_paste_modal.vue index 9340e7924..bf3ef1ebd 100644 --- a/app/javascript/vue/shared/content/attachments/clipboard_paste_modal.vue +++ b/app/javascript/vue/shared/content/attachments/clipboard_paste_modal.vue @@ -12,29 +12,68 @@