Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add multiple files per snippet #43

Merged
merged 32 commits into from May 31, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
eef5eab
Add multiple files per snippet
GWillmann Apr 8, 2019
7a8808f
Merge branch 'pr/add-files-to-snippets' of https://github.com/Kinoba/…
vavgustov Apr 20, 2019
98779e6
Replaces chromedriver-helper gem by webdrivers gem
GWillmann Apr 28, 2019
bf4d058
Snippet files improvements
GWillmann Apr 28, 2019
0c407ff
Merge branch 'pr/add-files-to-snippets' of https://github.com/Kinoba/…
vavgustov May 2, 2019
7d83d4c
Use 'main' as default file name for snippet -> snippet file conversion.
vavgustov May 2, 2019
ecd2794
Make collapsible link more simple. Remove semicolons.
vavgustov May 2, 2019
118bb1a
Fixed markdown view and copy to clipboard for show mode. Various expe…
vavgustov May 2, 2019
cd199c8
Fixed language syntax highlighting for markdown files. Fixed copy to …
vavgustov May 3, 2019
ad53f56
One more fix for collapsed + copy workflow.
vavgustov May 3, 2019
cd58516
Change underscore_case to camelCase naming in vue and js files
GWillmann May 7, 2019
7715384
Fixed initial highlighting for edit mode.
vavgustov May 28, 2019
ad92322
Improvements for camelCase + cleanup.
vavgustov May 28, 2019
e58c879
Quick dirty draft for improved edit mode (step 6).
vavgustov May 28, 2019
79539be
Rename app_serializer to active_model_serializers.
vavgustov May 28, 2019
5c9d556
Remove app_serializer.rb
vavgustov May 28, 2019
aa5ea6e
More improvements for edit mode.
vavgustov May 28, 2019
ad2959b
Improved typography.
vavgustov May 28, 2019
9d71aee
Removed last semicolon from js files.
vavgustov May 28, 2019
8b50a69
Fixed name for SnippetFileSerializer.
vavgustov May 29, 2019
b6427cf
Editable snippet should not change state for other UI elements until …
vavgustov May 29, 2019
5d2bec8
Make UI changes compatible with specs.
vavgustov May 30, 2019
cb4a5e0
Quick initial styles cleanup.
vavgustov May 30, 2019
10ae109
Always reset editable state when user click on edit.
vavgustov May 30, 2019
9be7cbd
When user click 'enter' submit form instead of add new file.
vavgustov May 30, 2019
96865ce
Improved backend performance.
vavgustov May 31, 2019
ccc9f9b
Improved calls to editable copies.
vavgustov May 31, 2019
cc06250
Fixed console error when switch between snippets with different amoun…
vavgustov May 31, 2019
d492256
Improved devices support. Cleanup.
vavgustov May 31, 2019
2cde822
Destroy snippets only after edit form submit.
vavgustov May 31, 2019
35eb7ad
Improved animations for non-Chrome browsers.
vavgustov May 31, 2019
3179569
Hm.. upgrade schema.
vavgustov May 31, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion Gemfile
Expand Up @@ -42,10 +42,10 @@ group :test do
gem 'database_cleaner', '~> 1.7'
gem 'capybara', '~> 3.15'
gem 'selenium-webdriver', '~> 3.13'
gem 'chromedriver-helper', '~> 1.2'
gem 'rails-controller-testing', '~> 1.0'
gem 'shoulda-matchers', '~> 3.1'
gem 'simplecov', '~> 0.14.1', require: false
gem 'webdrivers', '~> 3.0'
end

gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
12 changes: 5 additions & 7 deletions Gemfile.lock
Expand Up @@ -52,8 +52,6 @@ GEM
after_commit_action (1.1.0)
activerecord (>= 3.0.0)
activesupport (>= 3.0.0)
archive-zip (0.12.0)
io-like (~> 0.3.0)
arel (9.0.0)
awesome_print (1.8.0)
bcrypt (3.1.12)
Expand All @@ -79,9 +77,6 @@ GEM
activesupport
childprocess (0.9.0)
ffi (~> 1.0, >= 1.0.11)
chromedriver-helper (1.2.0)
archive-zip (~> 0.10)
nokogiri (~> 1.8)
coderay (1.1.2)
concurrent-ruby (1.1.5)
counter_culture (1.12.0)
Expand Down Expand Up @@ -120,7 +115,6 @@ GEM
activesupport (>= 4.2.0)
i18n (1.6.0)
concurrent-ruby (~> 1.0)
io-like (0.3.0)
json (2.2.0)
jsonapi-renderer (0.2.0)
listen (3.1.5)
Expand Down Expand Up @@ -247,6 +241,10 @@ GEM
activemodel (>= 5.0)
bindex (>= 0.4.0)
railties (>= 5.0)
webdrivers (3.8.0)
nokogiri (~> 1.6)
rubyzip (~> 1.0)
selenium-webdriver (~> 3.0)
webpacker (4.0.0.pre.pre.2)
activesupport (>= 4.2)
rack-proxy (>= 0.6.1)
Expand All @@ -267,7 +265,6 @@ DEPENDENCIES
binding_of_caller (~> 0.8.0)
bootsnap (~> 1.3)
capybara (~> 3.15)
chromedriver-helper (~> 1.2)
counter_culture (~> 1.12)
database_cleaner (~> 1.7)
debug-extras
Expand All @@ -290,6 +287,7 @@ DEPENDENCIES
tzinfo-data
uglifier (~> 4.1)
web-console (~> 3.7)
webdrivers (~> 3.0)
webpacker (= 4.0.0.pre.pre.2)

RUBY VERSION
Expand Down
5 changes: 4 additions & 1 deletion app/controllers/api/v1/data_controller.rb
@@ -1,9 +1,12 @@
class Api::V1::DataController < Api::BaseController
def default_state
snippets = Snippet.includes(:snippet_files, :label)

data = {
snippets: ActiveModelSerializers::SerializableResource.new(Snippet.all, each_serializer: ::SnippetSerializer),
snippets: ActiveModelSerializers::SerializableResource.new(snippets, each_serializer: ::SnippetSerializer),
languages: Editor.languages
}

render json: data
end
end
9 changes: 7 additions & 2 deletions app/controllers/api/v1/snippets_controller.rb
Expand Up @@ -2,6 +2,7 @@ class Api::V1::SnippetsController < Api::BaseController
include ResponseData

before_action :set_snippet, except: :create
before_action :set_snippet_file, only: [:raw]

def create
@snippet = Snippet.new(snippet_params)
Expand All @@ -21,7 +22,7 @@ def destroy
end

def raw
render plain: @snippet.content
render plain: @snippet_file.content
end

private
Expand All @@ -30,9 +31,13 @@ def set_snippet
@snippet = Snippet.find(params[:id])
end

def set_snippet_file
@snippet_file = @snippet.snippet_files.find_by(id: params[:snippet_file])
end

def snippet_params
# TODO: it's legacy for core counter_cache issues
data = params.require(:snippet).permit(:title, :content, :language, :tabs, label_attributes: [:name])
data = params.require(:snippet).permit(:title, :description, snippet_files_attributes: [:id, :title, :content, :language, :tabs, :_destroy], label_attributes: [:name])
label = data[:label_attributes]['name'].blank? ? nil : Label.find_or_create_by(name: data[:label_attributes]['name'])
data.except(:label_attributes).merge(label: label)
end
Expand Down
3 changes: 3 additions & 0 deletions app/javascript/packs/common.js
@@ -1,5 +1,6 @@
import Rails from 'rails-ujs'
import Notifications from '../snibox/utils/notifications'
import smoothscroll from 'smoothscroll-polyfill'

import '../styles/application.scss'

Expand Down Expand Up @@ -49,3 +50,5 @@ const confirmed = (element, result) => {
Rails.delegate(document, 'a[data-confirm-swal]', 'click', handleConfirm)

Rails.start()

smoothscroll.polyfill()
31 changes: 22 additions & 9 deletions app/javascript/snibox/api/backend.js
Expand Up @@ -11,7 +11,7 @@ class BackendService {

// create or update
save(callback = null) {
let error_message = this.options.messages.error
let errorMessage = this.options.messages.error
axios[this.options.method](this.options.path, this.options.data)
.then(
response => {
Expand All @@ -21,17 +21,17 @@ class BackendService {
else {
// render error notification from api
if (response.data.hasOwnProperty('errors')) {
error_message += '<hr/>'
errorMessage += '<hr/>'
response.data.errors.forEach(error => {
error_message = error_message + error + '.<br/>'
errorMessage = errorMessage + error + '.<br/>'
})
}
Notifications.toast.error(error_message)
Notifications.toast.error(errorMessage)
}
})
.catch(error => {
console.log(error)
Notifications.toast.error(error_message)
Notifications.toast.error(errorMessage)
})
}

Expand Down Expand Up @@ -65,13 +65,26 @@ class BackendService {

class SnippetService extends BackendService {
save() {
let snippetFilesAttributes = []
this.component.$store.state.labelSnippets.edit.snippetFiles.forEach((snippetFile, index) => {
snippetFilesAttributes.push({
id: snippetFile.id || null,
title: snippetFile.title,
content: this.component.$children[0].$children[index].editor.getValue(),
language: snippetFile.language,
tabs: snippetFile.tabs
})
if (snippetFile.hasOwnProperty('_destroy')) {
snippetFilesAttributes[snippetFilesAttributes.length - 1]['_destroy'] = true
}
})

this.options.data = {
snippet: {
id: this.component.snippet.id,
title: this.component.$store.state.labelSnippets.edit.title,
content: this.component.editor.getValue(),
language: this.component.$store.state.labelSnippets.edit.language,
tabs: this.component.$store.state.labelSnippets.edit.tabs,
description: this.component.$store.state.labelSnippets.edit.description,
snippet_files_attributes: snippetFilesAttributes,
label_attributes: {
name: this.component.$store.state.labelSnippets.edit.label
}
Expand Down Expand Up @@ -141,7 +154,7 @@ export default {
}

new SnippetService(component, options).destroy()
}
},
},

label: {
Expand Down
41 changes: 41 additions & 0 deletions app/javascript/snibox/components/CollapsibleControls.vue
@@ -0,0 +1,41 @@
<template>
<a :id="`snippet-collapse-${index}`"
class="card-header-icon"
@click="collapseCardContent">
<icon v-if="collapse"
type="chevron-right"/>
<icon v-if="!collapse"
type="chevron-down"/>
</a>
</template>

<script>
import Icon from './Icon.vue'

export default {
name: 'collapsible-controls',

props: ['index', 'id'],

components: {Icon},

data() {
return {
collapse: false
}
},

methods: {
collapseCardContent(e) {
e.preventDefault()

if (this.collapse) {
this.$root.$el.querySelector(this.id + ' .card-content').classList.remove('collapsed')
} else {
this.$root.$el.querySelector(this.id + ' .card-content').classList.add('collapsed')
}
this.collapse = !this.collapse
}
}
}
</script>
4 changes: 4 additions & 0 deletions app/javascript/snibox/components/Repository.vue
Expand Up @@ -35,6 +35,10 @@
computed: {
showSnippet() {
return this.$store.state.labelSnippets.mode
},

snippet() {
return this.$store.state.labelSnippets.active
}
},

Expand Down
11 changes: 6 additions & 5 deletions app/javascript/snibox/components/SearchBox.vue
Expand Up @@ -46,10 +46,11 @@
maxPatternLength: 32,
minMatchCharLength: 1,
keys: [
'content',
'title',
'label.name',
'language'
'description',
'snippetFiles.content',
'snippetFiles.title',
'snippetFiles.language',
'label.name'
]
}

Expand All @@ -69,7 +70,7 @@

mounted() {
document.addEventListener('keyup', e => {
if (e.key === '/' && !['INPUT', 'TEXTAREA'].includes(document.activeElement.tagName)) {
if ((e.key === '/' || e.key === '>') && !['INPUT', 'TEXTAREA'].includes(document.activeElement.tagName)) {
this.$el.querySelector('.search').focus()
}

Expand Down