task lists
This commit is contained in:
parent
18603dc783
commit
b1e5c22101
@ -2,7 +2,7 @@ class TaskItemsController < ApplicationController
|
||||
|
||||
before_action :ensure_valid_user
|
||||
before_action :set_task_list
|
||||
before_action :set_task_item, only: [:update, :destroy]
|
||||
before_action :set_task_item, only: [:update]
|
||||
|
||||
def create
|
||||
@task_item = TaskItem.new(task_item_params)
|
||||
@ -24,7 +24,23 @@ class TaskItemsController < ApplicationController
|
||||
end
|
||||
|
||||
def destroy
|
||||
@task_item.destroy
|
||||
ids = Array.wrap(params[:id]) + Array.wrap(params[:ids])
|
||||
TaskItem.transaction do
|
||||
@task_items = @task_list.task_items.find(ids)
|
||||
@task_items.each { |i| i.destroy }
|
||||
end
|
||||
|
||||
head :no_content
|
||||
end
|
||||
|
||||
def complete
|
||||
ids = Array.wrap(params[:id]) + Array.wrap(params[:ids])
|
||||
new_status = !params[:invert].present?
|
||||
TaskItem.transaction do
|
||||
@task_items = @task_list.task_items.find(ids)
|
||||
@task_items.each { |i| i.update_attribute(:completed, new_status) }
|
||||
end
|
||||
|
||||
head :no_content
|
||||
end
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div class="dropdown" :class="{'is-active': open}">
|
||||
<div class="dropdown" :class="{'is-active': open, 'is-hoverable': hover}">
|
||||
<div class="dropdown-trigger">
|
||||
<slot name="button">
|
||||
<button type="button" class="button" :class="buttonClass" @click="toggle">
|
||||
<span>{{ label }}</span>
|
||||
<app-icon icon="caret-bottom"></app-icon>
|
||||
<app-icon icon="caret-bottom" size="xs"></app-icon>
|
||||
</button>
|
||||
</slot>
|
||||
</div>
|
||||
@ -24,8 +24,15 @@
|
||||
export default {
|
||||
props: {
|
||||
open: {
|
||||
required: true,
|
||||
type: Boolean
|
||||
required: false,
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
|
||||
hover: {
|
||||
required: false,
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
|
||||
label: {
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<span class="icon" :class="sizeClass" @click="$emit('click', $event)">
|
||||
<img ref="img" :class="['iconic', 'iconic-fluid', size]" :data-src="iconUrl" v-bind="extraIconAttributes" :style="{padding: svgPadding}" />
|
||||
<img ref="img" :class="['iconic', 'iconic-fluid', size]" v-bind="extraIconAttributes" :style="{padding: svgPadding}" />
|
||||
</span>
|
||||
</template>
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
import CircleCheck from "../iconic/svg/smart/circle-check";
|
||||
import Link from "../iconic/svg/smart/link";
|
||||
import Lock from "../iconic/svg/smart/lock";
|
||||
import Menu from "../iconic/svg/smart/menu";
|
||||
import Person from "../iconic/svg/smart/person";
|
||||
import Pencil from "../iconic/svg/smart/pencil";
|
||||
import Star from "../iconic/svg/smart/star";
|
||||
@ -26,7 +27,8 @@
|
||||
class IconData {
|
||||
constructor(url, dataAttributes) {
|
||||
this.url = url;
|
||||
this.dataAttributes = dataAttributes || [];
|
||||
this.dataAttributes = dataAttributes || {};
|
||||
this.dataAttributes['src'] = url;
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,6 +48,7 @@
|
||||
'link-intact': new IconData(Link, {state: 'intact'}),
|
||||
'lock-locked': new IconData(Lock, {state: 'locked'}),
|
||||
'lock-unlocked': new IconData(Lock, {state: 'unlocked'}),
|
||||
menu: new IconData(Menu),
|
||||
pencil: new IconData(Pencil),
|
||||
person: new IconData(Person),
|
||||
star: new IconData(Star),
|
||||
@ -54,6 +57,7 @@
|
||||
};
|
||||
|
||||
const sizeMap = {
|
||||
xs: new SizeData('is-small', '25%'),
|
||||
sm: new SizeData('is-small'),
|
||||
md: new SizeData(''),
|
||||
lg: new SizeData('is-medium'),
|
||||
@ -93,10 +97,6 @@
|
||||
return sizeMap[this.size];
|
||||
},
|
||||
|
||||
iconUrl() {
|
||||
return this.iconData.url;
|
||||
},
|
||||
|
||||
extraIconAttributes() {
|
||||
const attrs = {};
|
||||
|
||||
@ -117,16 +117,20 @@
|
||||
|
||||
mounted() {
|
||||
const self = this;
|
||||
iconicInstance.inject(this.$refs.img, {
|
||||
each: function(svg) { self.injectedSvg = svg; }
|
||||
setTimeout(() => {
|
||||
iconicInstance.inject(this.$refs.img, {
|
||||
each: function(svg) { self.injectedSvg = svg; }
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
updated() {
|
||||
for(let attr in this.extraIconAttributes) {
|
||||
this.injectedSvg.setAttribute(attr, this.extraIconAttributes[attr]);
|
||||
if (this.injectedSvg) {
|
||||
for(let attr in this.extraIconAttributes) {
|
||||
this.injectedSvg.setAttribute(attr, this.extraIconAttributes[attr]);
|
||||
}
|
||||
iconicInstance.update(this.injectedSvg);
|
||||
}
|
||||
iconicInstance.update(this.injectedSvg);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
<td>
|
||||
<div class="check">
|
||||
<app-icon v-if="i.completed" icon="check"></app-icon>
|
||||
<span class="icon" v-else></span>
|
||||
</div>
|
||||
</td>
|
||||
<td>{{ i.name }}</td>
|
||||
@ -92,7 +93,8 @@
|
||||
methods: {
|
||||
...mapActions([
|
||||
'createTaskItem',
|
||||
'updateTaskItem'
|
||||
'updateTaskItem',
|
||||
'completeTaskItems'
|
||||
]),
|
||||
|
||||
save() {
|
||||
@ -107,11 +109,13 @@
|
||||
},
|
||||
|
||||
toggleItem(i) {
|
||||
const item = cloneDeep(i);
|
||||
item.completed = !item.completed;
|
||||
this.loadResource(
|
||||
this.updateTaskItem(item)
|
||||
)
|
||||
this.completeTaskItems({
|
||||
taskList: this.taskList,
|
||||
taskItems: [i],
|
||||
completed: !i.completed
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
toggleShowAddItem() {
|
||||
@ -130,6 +134,8 @@
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@import "../styles/variables";
|
||||
|
||||
.columns {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
@ -142,4 +148,8 @@
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
div.check .icon {
|
||||
border: 2px solid $link;
|
||||
}
|
||||
|
||||
</style>
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
|
||||
<div class="dropdown-item" @mouseover="hovering = true" @mouseleave="hovering = false" :class="{hovered: hovering, 'is-active': active}" @click="selectList">
|
||||
<span>{{taskList.name}}</span>
|
||||
<span>{{taskList.name}} ({{ taskList.task_items.length }})</span>
|
||||
<button @click.stop="confirmingDelete = true" class="button is-small is-danger is-pulled-right"><app-icon icon="x" size="sm"></app-icon></button>
|
||||
<div class="is-clearfix"></div>
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
<app-pager :current-page="currentPage" :total-pages="totalPages" paged-item-name="recipe" @changePage="changePage"></app-pager>
|
||||
|
||||
<table class="table is-fullwidth">
|
||||
<table class="table is-fullwidth" :class="{ small: mediaQueries.touch }">
|
||||
<thead>
|
||||
<tr>
|
||||
<th v-for="h in tableHeader" :key="h.name">
|
||||
@ -52,23 +52,30 @@
|
||||
<td class="recipe-time">{{ formatRecipeTime(r.total_time, r.active_time) }}</td>
|
||||
<td><app-date-time :date-time="r.created_at" :show-time="false"></app-date-time></td>
|
||||
<td>
|
||||
<div class="field is-grouped">
|
||||
<div class="control">
|
||||
<router-link v-if="isLoggedIn" :to="{name: 'new_log', params: { recipeId: r.id } }" class="button is-primary">
|
||||
<app-icon icon="star" size="md"></app-icon>
|
||||
<app-dropdown hover v-if="isLoggedIn" class="is-right">
|
||||
<button slot="button" class="button">
|
||||
<app-icon icon="menu"></app-icon>
|
||||
</button>
|
||||
|
||||
<div class="dropdown-item">
|
||||
<router-link :to="{name: 'new_log', params: { recipeId: r.id } }" class="button is-primary is-fullwidth">
|
||||
<app-icon icon="star" size="md"></app-icon> <span>Add Log Entry</span>
|
||||
</router-link>
|
||||
</div>
|
||||
<div class="control">
|
||||
<router-link v-if="isLoggedIn" :to="{name: 'edit_recipe', params: { id: r.id } }" class="button is-primary">
|
||||
<app-icon icon="pencil" size="md"></app-icon>
|
||||
|
||||
<div class="dropdown-item">
|
||||
<router-link :to="{name: 'edit_recipe', params: { id: r.id } }" class="button is-primary is-fullwidth">
|
||||
<app-icon icon="pencil" size="md"></app-icon> <span>Edit Recipe</span>
|
||||
</router-link>
|
||||
</div>
|
||||
<div class="control">
|
||||
<button v-if="isLoggedIn" type="button" class="button is-danger" @click="deleteRecipe(r)">
|
||||
<app-icon icon="x" size="md"></app-icon>
|
||||
|
||||
<div class="dropdown-item">
|
||||
<button type="button" class="button is-danger is-fullwidth" @click="deleteRecipe(r)">
|
||||
<app-icon icon="x" size="md"></app-icon> <span>Delete Recipe</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</app-dropdown>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@ -85,6 +92,7 @@
|
||||
|
||||
import api from "../lib/Api";
|
||||
import debounce from "lodash/debounce";
|
||||
import { mapState } from "vuex";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
@ -103,6 +111,9 @@
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState([
|
||||
"mediaQueries"
|
||||
]),
|
||||
recipes() {
|
||||
if (this.recipeData) {
|
||||
return this.recipeData.recipes;
|
||||
@ -227,4 +238,17 @@
|
||||
.recipe-time {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.table th {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.table.small {
|
||||
td, th {
|
||||
&:nth-of-type(3), &:nth-of-type(4), &:nth-of-type(5), &:nth-of-type(6) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Tasks</h1>
|
||||
<h1 class="title is-3">Tasks</h1>
|
||||
|
||||
<app-dropdown button-class="is-primary" :open="showListDropdown" :label="listSelectLabel" @open="showListDropdown = true" @close="showListDropdown = false">
|
||||
|
||||
@ -11,10 +11,19 @@
|
||||
<task-list-mini-form :task-list="newList" :validation-errors="newListValidationErrors" @save="saveNewList"></task-list-mini-form>
|
||||
</div>
|
||||
</app-dropdown>
|
||||
<br><br>
|
||||
|
||||
<div v-if="currentTaskList !== null">
|
||||
|
||||
<task-item-list :task-list="currentTaskList"></task-item-list>
|
||||
<div class="box">
|
||||
<button class="button" @click="deleteCompletedItems">Clear Completed</button>
|
||||
<button class="button" @click="completeAllItems">Check All</button>
|
||||
<button class="button" @click="unCompleteAllItems">Uncheck All</button>
|
||||
</div>
|
||||
|
||||
<div class="box">
|
||||
<task-item-list :task-list="currentTaskList"></task-item-list>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@ -64,7 +73,9 @@
|
||||
...mapActions([
|
||||
'refreshTaskLists',
|
||||
'createTaskList',
|
||||
'deleteTaskList'
|
||||
'deleteTaskList',
|
||||
'deleteTaskItems',
|
||||
'completeTaskItems'
|
||||
]),
|
||||
...mapMutations([
|
||||
'setCurrentTaskList'
|
||||
@ -88,6 +99,46 @@
|
||||
this.loadResource(
|
||||
this.deleteTaskList(list)
|
||||
);
|
||||
},
|
||||
|
||||
completeAllItems() {
|
||||
const toComplete = this.currentTaskList.task_items.filter(i => !i.completed);
|
||||
this.loadResource(
|
||||
this.completeTaskItems({
|
||||
taskList: this.currentTaskList,
|
||||
taskItems: toComplete,
|
||||
completed: true
|
||||
})
|
||||
)
|
||||
},
|
||||
|
||||
unCompleteAllItems() {
|
||||
const toUnComplete = this.currentTaskList.task_items.filter(i => i.completed);
|
||||
this.loadResource(
|
||||
this.completeTaskItems({
|
||||
taskList: this.currentTaskList,
|
||||
taskItems: toUnComplete,
|
||||
completed: false
|
||||
})
|
||||
)
|
||||
},
|
||||
|
||||
deleteCompletedItems() {
|
||||
this.loadResource(
|
||||
this.deleteTaskItems({
|
||||
taskList: this.currentTaskList,
|
||||
taskItems: this.currentTaskList.task_items.filter(i => i.completed)
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
deleteAllItems() {
|
||||
this.loadResource(
|
||||
this.deleteTaskItems({
|
||||
taskList: this.currentTaskList,
|
||||
taskItems: this.currentTaskList.task_items
|
||||
})
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -403,8 +403,23 @@ class Api {
|
||||
return this.patch(`/task_lists/${listId}/task_items/${taskItem.id}`, params);
|
||||
}
|
||||
|
||||
deleteTaskItem(listId, taskItem) {
|
||||
return this.del(`/task_lists/${listId}/task_items/${taskItem.id}`);
|
||||
deleteTaskItems(listId, taskItems) {
|
||||
const params = {
|
||||
ids: taskItems.map(i => i.id)
|
||||
};
|
||||
return this.del(`/task_lists/${listId}/task_items/`, params);
|
||||
}
|
||||
|
||||
completeTaskItems(listId, taskItems, invert = false) {
|
||||
const params = {
|
||||
ids: taskItems.map(i => i.id)
|
||||
};
|
||||
|
||||
if (invert === true) {
|
||||
params.invert = true;
|
||||
}
|
||||
|
||||
return this.patch(`/task_lists/${listId}/task_items/complete`, params);
|
||||
}
|
||||
|
||||
getAdminUserList() {
|
||||
|
@ -97,14 +97,26 @@ export default new Vuex.Store({
|
||||
}
|
||||
},
|
||||
|
||||
removeTaskItem(state, item) {
|
||||
const listId = item.task_list_id;
|
||||
removeTaskItems(state, payload) {
|
||||
const listId = payload.taskList.id;
|
||||
const list = state.taskLists.find(l => l.id === listId);
|
||||
if (list) {
|
||||
const taskIdx = list.task_items.findIndex(i => i.id === item.id);
|
||||
if (taskIdx >= 0) {
|
||||
list.task_items.splice(taskIdx, 1);
|
||||
}
|
||||
|
||||
list.task_items = list.task_items.filter(item => {
|
||||
return payload.taskItems.findIndex(i => i.id === item.id) === -1;
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
setTaskItemCompletion(state, payload) {
|
||||
const listId = payload.taskList.id;
|
||||
const list = state.taskLists.find(l => l.id === listId);
|
||||
if (list) {
|
||||
list.task_items.forEach(item => {
|
||||
if (payload.taskItems.findIndex(i => i.id === item.id) >= 0) {
|
||||
item.completed = payload.completed;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -182,9 +194,14 @@ export default new Vuex.Store({
|
||||
});
|
||||
},
|
||||
|
||||
deleteTaskItem({commit}, taskItem) {
|
||||
return api.deleteTaskItem(taskItem.task_list_id, taskItem)
|
||||
.then(() => commit("removeTaskItem", taskItem));
|
||||
deleteTaskItems({commit}, payload) {
|
||||
return api.deleteTaskItems(payload.taskList.id, payload.taskItems)
|
||||
.then(() => commit("removeTaskItems", payload));
|
||||
},
|
||||
|
||||
completeTaskItems({commit}, payload) {
|
||||
return api.completeTaskItems(payload.taskList.id, payload.taskItems, !payload.completed)
|
||||
.then(() => commit("setTaskItemCompletion", payload));
|
||||
}
|
||||
}
|
||||
});
|
@ -1,10 +1,11 @@
|
||||
|
||||
<%
|
||||
manifest_data = Webpacker::manifest.refresh
|
||||
pack_assets = manifest_data.values.select { |asset| asset !~ /\.map$/ } # [asset_pack_path("application.js"), asset_pack_path("application.css")].select { |a| a.present? }
|
||||
manifest_timestamp = File.mtime(Webpacker::config.public_manifest_path).to_i
|
||||
pack_assets = manifest_data.values.select { |asset| asset !~ /\.map$/ }
|
||||
%>
|
||||
|
||||
var cacheName = "parsley-cache-<%= File.mtime(Webpacker::config.public_manifest_path).to_i %>";
|
||||
var cacheName = "parsley-cache-<%= manifest_timestamp %>";
|
||||
|
||||
var staticAssets = [
|
||||
"/"
|
||||
@ -27,7 +28,7 @@ self.addEventListener('activate', function(event) {
|
||||
caches.keys().then(function (keyList) {
|
||||
return Promise.all(keyList.map(function (key) {
|
||||
if (key !== cacheName) {
|
||||
console.log('[ServiceWorker] Removing old cache', key);
|
||||
console.log(`[ServiceWorker] Removing old cache: ${key}`);
|
||||
return caches.delete(key);
|
||||
}
|
||||
}));
|
||||
@ -42,7 +43,7 @@ self.addEventListener('fetch', function(event) {
|
||||
|
||||
// Any non-GET or non-http(s) request should be ignored
|
||||
if (event.request.method !== 'GET' || event.request.url.indexOf('http') !== 0) {
|
||||
return fetch(event.request);
|
||||
return;
|
||||
}
|
||||
|
||||
// Cache-first response for static assets
|
||||
|
@ -34,7 +34,12 @@ Rails.application.routes.draw do
|
||||
end
|
||||
|
||||
resources :task_lists, only: [:index, :show, :create, :update, :destroy] do
|
||||
resources :task_items, only: [:create, :update, :destroy]
|
||||
resources :task_items, only: [:create, :update] do
|
||||
collection do
|
||||
delete '/', action: :destroy, as: :destroy
|
||||
patch 'complete', action: :complete
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
resource :user, only: [:new, :create, :edit, :update]
|
||||
|
@ -83,6 +83,7 @@ ActiveRecord::Schema.define(version: 2018_09_06_191333) do
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.text "preparation"
|
||||
t.integer "recipe_as_ingredient_id"
|
||||
t.index ["recipe_id"], name: "index_recipe_ingredients_on_recipe_id"
|
||||
end
|
||||
|
||||
|
80
spec/controllers/task_item_controller_spec.rb
Normal file
80
spec/controllers/task_item_controller_spec.rb
Normal file
@ -0,0 +1,80 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe TaskItemsController, type: :controller do
|
||||
|
||||
render_views
|
||||
|
||||
before(:each) do
|
||||
request.accept = "application/json"
|
||||
end
|
||||
|
||||
let(:user) {
|
||||
create(:user)
|
||||
}
|
||||
|
||||
let(:task_list) { create(:task_list, user: user) }
|
||||
|
||||
let(:valid_session) { {user_id: user.id} }
|
||||
|
||||
describe 'POST #create' do
|
||||
it 'creates a task_item' do
|
||||
expect do
|
||||
post :create, params: {task_list_id: task_list.id, task_item: {name: 'name'}}, session: valid_session
|
||||
end.to change(TaskItem, :count).by 1
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PATCH #update' do
|
||||
it 'updates a task_item' do
|
||||
i = create(:task_item, task_list: task_list)
|
||||
patch :update, params: {task_list_id: task_list.id, id: i.id, task_item: {name: 'new name'}}, session: valid_session
|
||||
i.reload
|
||||
expect(i.name).to eq 'new name'
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE #destroy' do
|
||||
it 'destroys the item' do
|
||||
i = create(:task_item, task_list: task_list)
|
||||
delete :destroy, params: {task_list_id: task_list.id, id: i.id}, session: valid_session
|
||||
expect(TaskItem.where(id: i.id).count).to eq 0
|
||||
end
|
||||
|
||||
it 'destroys an array of items' do
|
||||
i1 = create(:task_item, task_list: task_list)
|
||||
i2 = create(:task_item, task_list: task_list)
|
||||
i3 = create(:task_item, task_list: task_list)
|
||||
delete :destroy, params: {task_list_id: task_list.id, ids: [i1.id, i2.id, i3.id]}, session: valid_session
|
||||
expect(TaskItem.where(id: [i1.id, i2.id, i3.id]).count).to eq 0
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PATCH complete' do
|
||||
it 'sets all given items to completed' do
|
||||
i1 = create(:task_item, task_list: task_list)
|
||||
i2 = create(:task_item, task_list: task_list)
|
||||
i3 = create(:task_item, task_list: task_list)
|
||||
|
||||
patch :complete, params: {task_list_id: task_list.id, ids: [i1.id, i2.id, i3.id]}, session: valid_session
|
||||
|
||||
[i1, i2, i3].each do |i|
|
||||
i.reload
|
||||
expect(i.completed).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
it 'sets all given items to not completed' do
|
||||
i1 = create(:task_item, task_list: task_list)
|
||||
i2 = create(:task_item, task_list: task_list)
|
||||
i3 = create(:task_item, task_list: task_list)
|
||||
|
||||
patch :complete, params: {task_list_id: task_list.id, ids: [i1.id, i2.id, i3.id], invert: true}, session: valid_session
|
||||
|
||||
[i1, i2, i3].each do |i|
|
||||
i.reload
|
||||
expect(i.completed).to be_falsey
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
@ -3,5 +3,6 @@ FactoryBot.define do
|
||||
task_list
|
||||
name "MyString"
|
||||
quantity "MyString"
|
||||
completed false
|
||||
end
|
||||
end
|
||||
|
@ -1,5 +1,5 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe TaskItem, type: :model do
|
||||
pending "add some examples to (or delete) #{__FILE__}"
|
||||
|
||||
end
|
||||
|
@ -1,5 +1,5 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe TaskList, type: :model do
|
||||
pending "add some examples to (or delete) #{__FILE__}"
|
||||
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user