flameresttable 1.0.5 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.eslintrc CHANGED
@@ -15,7 +15,8 @@
15
15
  "vue/multi-word-component-names": "off",
16
16
  "vue/no-multiple-template-root": "off",
17
17
  "vue/no-duplicate-attributes": "off",
18
- "linebreak-style": "off"
18
+ "linebreak-style": "off",
19
+ "vue/multiline-html-element-content-newline": "off"
19
20
  },
20
21
  "plugins": [
21
22
  "@typescript-eslint"
@@ -7,5 +7,8 @@
7
7
  "plaintext": "html"
8
8
  },
9
9
  "tailwindCSS.emmetCompletions": true,
10
- "css.lint.unknownAtRules": "ignore"
10
+ "css.lint.unknownAtRules": "ignore",
11
+ "editor.codeActionsOnSave": {
12
+ "source.fixAll": true
13
+ },
11
14
  }
package/README.md CHANGED
@@ -1,39 +1,13 @@
1
- # Vue 3 + Vite + Pinia + Router + Tailwind + Pug + Typescript template
1
+ # Smart REST Table on Vue 3 + Vite + Pinia
2
2
 
3
- Hello, world!
3
+ // Обработчик после загрузки
4
+ opts.Popup.load = async (row: any) => {
4
5
 
5
- That starter for rapid prototyping a services. Start with
6
+ }
6
7
 
7
- git clone https://github.com/FlameArt/vuestarter.git ./projectName
8
-
9
- ## Under the hood
10
-
11
- * Vite
12
- * Vue 3 [via composition api]
13
- * Typescript
14
- * Pinia as state manager
15
- * Vue Router 4
16
- * Tailwind as css framework
17
- * Pug as html framework
18
- * ESLint
19
- * Capacitor as converter to Android and iOS apps
20
- * VSCode ready with Volar
21
- * [FlameREST](https://github.com/FlameArt/auto-rest-template-yii2) attached
22
- * Precreated Signup, Auth and Password Reset pages
23
-
24
- # VSCode improvements
25
-
26
- Pug-lexer in Volar doesn`t support all tailwind functions currently. So you need to apply fix https://github.com/pugjs/pug/pull/3373
27
-
28
- OR just fix the `Volar` extension directly in `%USERNAME%/.vscode/extensions/vue.volar-VERSION/dist/node/server.js` that
29
-
30
- (/^\.([_a-z0-9\-]*[_a-z][_a-z0-9\-]*)/i, 'class');
31
-
32
- to that
33
-
34
- (/^\.([_a-z0-9\-]*[_a-z]([_a-z0-9\-\[\]]|:(?! ))*)/i, 'class');
35
-
36
- Compilation works fine without any fixes
8
+ // Обработчик перед сохранением
9
+ opts.Popup.beforeEdit = async (row: any, table: typeof FlameTable.prototype): Promise<boolean> => {
10
+ }
37
11
 
38
12
  # Licenses
39
13
  MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flameresttable",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "main": "./src/plugin.ts",
5
5
  "repository": {
6
6
  "type": "git",
@@ -108,7 +108,7 @@ export class Column implements IColumn {
108
108
  // string - обычная строка или селектор строк
109
109
  // text - text area
110
110
  // button - кнопка
111
- popupType: 'string' as "string" | "text" | "button" | "date" | "selector",
111
+ popupType: 'string' as "string" | "text" | "button" | "date" | "selector" | "image" | "file",
112
112
 
113
113
  // Текст ошибки добавления/обновления
114
114
  errorMessage: '',
@@ -227,7 +227,7 @@ export interface IColumn {
227
227
  Popup?: {
228
228
 
229
229
  // Тут привязка к реальным данным
230
- model?: string,
230
+ model?: any,
231
231
 
232
232
  // Заголовок поля в попапе
233
233
  title?: string,
@@ -259,7 +259,7 @@ export interface IColumn {
259
259
  // string - обычная строка или селектор строк
260
260
  // text - text area
261
261
  // button - кнопка
262
- popupType?: "string" | "text" | "button" | "date" | "selector",
262
+ popupType?: "string" | "text" | "button" | "date" | "selector" | "image" | "file",
263
263
 
264
264
  // Текст ошибки добавления/обновления
265
265
  errorMessage?: string,
@@ -48,11 +48,6 @@ export default class FlameTable<T> {
48
48
  total: 0,
49
49
  })
50
50
 
51
- /**
52
- * Параметры прогрузки
53
- */
54
- public LoadParams = {} as any;
55
-
56
51
  /**
57
52
  * Открытая в попапе строка
58
53
  */
@@ -124,9 +119,9 @@ export default class FlameTable<T> {
124
119
  */
125
120
  public async update(SaveLoadParams: any = null) {
126
121
 
127
- if (SaveLoadParams !== null) this.LoadParams = SaveLoadParams;
122
+ if (SaveLoadParams !== null) this.opts.LoadParams = SaveLoadParams;
128
123
 
129
- const rows: Rows<T> = await (this.model as any).constructor.all(Object.assign(this.LoadParams, { page: this.Pager.page, perPage: this.Pager.perPage }));
124
+ const rows: Rows<T> = await (this.model as any).constructor.all(Object.assign(this.opts.LoadParams, { page: this.Pager.page, perPage: this.Pager.perPage }));
130
125
 
131
126
  this.load(rows);
132
127
 
@@ -1,66 +1,147 @@
1
- <template lang="pug">
2
- .mt-0
3
-
4
- // "ДОБАВИТЬ" И ЧИСЛО ЗАПИСЕЙ
5
- .flex.items-center.justify-between
6
- slot(name="defaultButtons")
7
- .flex.cursor-pointer.justify-center.items-center.text-white.block.bg-blue-600.font-medium.rounded.text-sm.px-4.text-center(v-show="$props.opts?.Add.can" @click="add()" class="hover:bg-blue-700 .focus:ring-4.focus:ring-blue-200.dark:focus:ring-blue-900")
8
- div.text-xl +
9
- div.ml-2 {{ $props.opts?.Add.buttonTitle }}
10
- slot(name="otherButtons")
11
- .text-xs.text-gray-400 Показано: {{ Table.Pager.total > Table.Pager.perPage * Table.Pager.page ? Table.Pager.perPage * Table.Pager.page : Table.Pager.total }} / {{ Table.Pager.total }} записей
12
-
13
- // ТАБЛИЦА
14
- .mt-2.table.w-full
15
-
16
- // ЗАГОЛОВКИ СТОЛБЦОВ
17
- .table-header-group
18
- .table-cell.border-r.border-r-slate-100.px-2(v-for="column in Table.columns" v-show="column.Table.isShow")
19
- span {{ column.title !== '' ? column.title : column.name }}
20
- .table-cell.border-r.border-r-slate-100.px-2(v-if="opts.Edit.can")
21
- button.bg-green-600.invisible Изменить
22
- .table-cell.border-r.border-r-slate-100.px-2(v-if="opts.Remove.can")
23
- button.bg-green-600.invisible Удалить
24
-
25
- // СТРОКИ
26
- .table-row-group
27
- .table-row.cursor-pointer(v-for="row in (Table.Rows.rows)" class="hover:bg-slate-100")
28
- .table-cell.border-r.border-r-slate-100.px-2(v-for="column in Table.columns" v-show="column.Table.isShow" @click="column.Table.click(row, column)" class="last:border-r-0 last:pr-0")
29
- span {{ column.Table.value(row, column) }}
30
- .table-cell.border-r.border-r-slate-100.px-2.text-center(v-if="opts.Edit.can")
31
- button.px-2.py-1.bg-green-600.text-white.my-1(@click="edit(row)") Изменить
32
- .table-cell.border-r.border-r-slate-100.px-2.text-center(v-if="opts.Remove.can")
33
- button.px-2.py-1.bg-gray-600.opacity-30.text-white.my-1(@click="deleteRow(row)") Удалить
34
-
35
- Paginator.mt-3(:table="Table")
36
-
37
- // МОДАЛКА ДОБАВЛЕНИЯ
38
- ModalVue(ref="FlameTableModal")
39
- template(v-slot)
40
- .bg-white.rounded-xl(:class="'w-full desktop:w-[777px]'")
41
-
42
- slot(name="header")
43
-
44
- // КОЛОНКИ ТАБЛИЦЫ
45
- label.flex.items-stretch.justify-center.w-full.my-1.ml-2(v-for="column in ColumnNames", v-show="Table.columns[column].Popup.isShow")
46
- .w-44.text-left.px-2.py-1.bg-slate-100
47
- div {{ Table.columns[column].Popup.title !== '' ? Table.columns[column].Popup.title === '' : Table.columns[column].title !== '' ? Table.columns[column].title : Table.columns[column].name }}
48
- .text-xs.text-slate-400 {{ Table.columns[column].Popup.desc }}
49
- .flex-1.mr-5.w-full.flex.flex-col.self-stretch(v-if="Table.columns[column].Popup.popupType === 'string' || Table.columns[column].Popup.popupType === 'text'")
50
- input.h-full.self-stretch.py-1.px-2.w-full.outline-none.border.border-slate-100(v-model="Table.columns[column].Popup.model", type="text", :disabled="!Table.columns[column].Popup.isEnabled", :placeholder="Table.columns[column].Popup.placeholder !== '' ? Table.columns[column].Popup.placeholder : Table.columns[column].title !== '' ? Table.columns[column].title : Table.columns[column].name")
51
- .flex-1.mr-5.w-full.flex.flex-col.self-stretch(v-if="Table.columns[column].Popup.popupType === 'date'")
52
- Datepicker(v-model="Table.columns[column].Popup.model" autoApply )
53
- .flex-1.mr-5.w-full.flex.flex-col.self-stretch(v-if="Table.columns[column].Popup.popupType === 'selector'")
54
- select.h-full.self-stretch.py-1.px-2.w-full.outline-none.border.border-slate-100(v-model="Table.columns[column].Popup.model")
55
- option(v-for="(selectorVal, selectorKey) in Table.columns[column].Popup.Selector.values" :value="getSelector(Table.columns[column].Popup.Selector.values, selectorKey, selectorVal)[1]") {{ getSelector(Table.columns[column].Popup.Selector.values, selectorKey, selectorVal)[0] }}
56
-
57
- // КНОПКИ СОХРАНЕНИЯ
58
- .flex.w-full.mt-3.mb-2.justify-between.items-center
59
- .cursor-pointer.ml-2.text-lg.py-2.text-white.block.bg-gray-400.font-medium.rounded.text-sm.px-4.text-center(v-show="$props.opts?.Add.can" @click="Table.OpenedRow = null; FlameTableModal?.close()" class="hover:bg-blue-700 focus:ring-4 focus:ring-blue-200 dark:focus:ring-blue-900") Отмена
60
- .cursor-pointer.ml-2.text-lg.py-2.mr-3.text-white.block.bg-blue-600.font-medium.rounded.text-sm.px-4.text-center(@click="SaveTable()" class="hover:bg-blue-700 focus:ring-4 focus:ring-blue-200 dark:focus:ring-blue-900") {{ Table.mode === 'add' ? 'Добавить' : 'Сохранить' }}
61
-
62
-
63
-
1
+ <template>
2
+ <div class="mt-0">
3
+
4
+ <!-- "ДОБАВИТЬ" И ЧИСЛО ЗАПИСЕЙ-->
5
+ <div class="flex items-center justify-between">
6
+ <slot name="defaultButtons">
7
+ <div v-show="$props.opts?.Add.can"
8
+ class="flex cursor-pointer justify-center items-center text-white block bg-blue-600 font-medium rounded text-sm px-4 text-center hover:bg-blue-700 .focus:ring-4.focus:ring-blue-200.dark:focus:ring-blue-900"
9
+ @click="add()">
10
+ <div class="text-xl">
11
+ +
12
+ </div>
13
+ <div class="ml-2">
14
+ {{ $props.opts?.Add.buttonTitle }}
15
+ </div>
16
+ </div>
17
+ </slot>
18
+ <slot name="otherButtons" />
19
+
20
+ <!-- ЧИСЛО ЗАПИСЕЙ -->
21
+ <div class="text-xs text-gray-400">
22
+ Показано: {{ Table.Pager.total > Table.Pager.perPage * Table.Pager.page ?
23
+ Table.Pager.perPage * Table.Pager.page : Table.Pager.total }} / {{ Table.Pager.total }} записей
24
+ </div>
25
+
26
+ </div>
27
+
28
+ <!-- ТАБЛИЦА-->
29
+ <div class="mt-2 table w-full">
30
+
31
+ <!-- ЗАГОЛОВКИ СТОЛБЦОВ-->
32
+ <div class="table-header-group">
33
+ <div v-for="column in Table.columns" v-show="column.Table.isShow" :key="'cheader_' + column"
34
+ class="table-cell border-r border-r-slate-100 px-2">
35
+ <span>{{ column.title !== '' ? column.title :
36
+ column.name }}</span>
37
+ </div>
38
+ <div v-if="opts.Edit.can" class="table-cell border-r border-r-slate-100 px-2">
39
+ <button class="bg-green-600 invisible">
40
+ Изменить
41
+ </button>
42
+ </div>
43
+ <div v-if="opts.Remove.can" class="table-cell border-r border-r-slate-100 px-2">
44
+ <button class="bg-green-600 invisible">
45
+ Удалить
46
+ </button>
47
+ </div>
48
+ </div>
49
+
50
+ <!-- СТРОКИ-->
51
+ <div class="table-row-group">
52
+
53
+ <div v-for="row in (Table.Rows.rows)" :key="'row_' + (row as any).id"
54
+ class="table-row cursor-pointer hover:bg-slate-100">
55
+ <div v-for="column in Table.columns" v-show="column.Table.isShow" :key="'tc_' + column"
56
+ class="table-cell border-r border-r-slate-100 px-2 last:border-r-0 last:pr-0"
57
+ @click="column.Table.click(row, column)">
58
+ <span>{{
59
+ column.Table.value(row, column) }}</span>
60
+ </div>
61
+ <div v-if="opts.Edit.can" class="table-cell border-r border-r-slate-100 px-2 text-center">
62
+ <button class="px-2 py-1 bg-green-600 text-white my-1" @click="edit(row)">
63
+ Изменить
64
+ </button>
65
+ </div>
66
+ <div v-if="opts.Remove.can" class="table-cell border-r border-r-slate-100 px-2 text-center">
67
+ <button class="px-2 py-1 bg-gray-600 opacity-30 text-white my-1" @click="deleteRow(row)">
68
+ Удалить
69
+ </button>
70
+ </div>
71
+ </div>
72
+ </div>
73
+
74
+ </div>
75
+ </div>
76
+
77
+ <!-- ПОСТРАНИЧНАЯ РАЗБИВКА -->
78
+ <Paginator class="mt-3" :table="Table" />
79
+
80
+ <!-- МОДАЛКА ДОБАВЛЕНИЯ-->
81
+ <ModalVue ref="FlameTableModal">
82
+ <template #default>
83
+ <div class="bg-white rounded-xl" :class="'w-full desktop:w-[777px]'">
84
+
85
+ <!-- СЛОТ ЗАГОЛОВКА ПОПАПА -->
86
+ <slot name="header" />
87
+
88
+ <!-- КОЛОНКИ ТАБЛИЦЫ-->
89
+ <label v-for="column in ColumnNames" v-show="Table.columns[column].Popup.isShow" :key="'c' + column"
90
+ class="flex items-stretch justify-center w-full my-1 ml-2">
91
+ <div class="text-left px-2 py-1 bg-slate-100" style="width: 110px">
92
+ <div>{{ Table.columns[column].Popup.title !== '' ? Table.columns[column].Popup.title === '' :
93
+ Table.columns[column].title !== '' ? Table.columns[column].title : Table.columns[column].name }}</div>
94
+ <div class="text-xs text-slate-400">{{ Table.columns[column].Popup.desc }}</div>
95
+ </div>
96
+ <div
97
+ v-if="Table.columns[column].Popup.popupType === 'string' || Table.columns[column].Popup.popupType === 'text'"
98
+ class="flex-1 mr-5 w-full flex flex-col self-stretch">
99
+ <input v-model="Table.columns[column].Popup.model"
100
+ class="h-full self-stretch py-1 px-2 w-full outline-none border border-slate-100" type="text"
101
+ :disabled="!Table.columns[column].Popup.isEnabled"
102
+ :placeholder="Table.columns[column].Popup.placeholder !== '' ? Table.columns[column].Popup.placeholder : Table.columns[column].title !== '' ? Table.columns[column].title : Table.columns[column].name">
103
+ </div>
104
+ <div v-if="Table.columns[column].Popup.popupType === 'date'"
105
+ class="flex-1 mr-5 w-full flex flex-col self-stretch">
106
+ <Datepicker v-model="Table.columns[column].Popup.model" :auto-apply="true" />
107
+ </div>
108
+ <div v-if="Table.columns[column].Popup.popupType === 'selector'"
109
+ class="flex-1 mr-5 w-full flex flex-col self-stretch"><select v-model="Table.columns[column].Popup.model"
110
+ class="h-full self-stretch py-1 px-2 w-full outline-none border border-slate-100">
111
+ <option v-for="(selectorVal, selectorKey) in Table.columns[column].Popup.Selector.values"
112
+ :key="'sel_' + selectorKey"
113
+ :value="getSelector(Table.columns[column].Popup.Selector.values, selectorKey, selectorVal)[1]">{{
114
+ getSelector(Table.columns[column].Popup.Selector.values, selectorKey, selectorVal)[0] }}</option>
115
+ </select></div>
116
+ <div v-if="Table.columns[column].Popup.popupType === 'image'"
117
+ class="flex-1 border border-slate-100 mr-5 w-full flex self-stretch">
118
+ <div class="flex-1"><img :src="fileGetData(Table.columns[column].Popup.model)"></div><!-- Загрузчик--><label
119
+ :for="'cfile_' + column"><svg class="my-auto cursor-pointer" width="24" height="24" viewbox="0 0 24 24"
120
+ fill="none" xmlns="http://www.w3.org/2000/svg">
121
+ <path fill-rule="evenodd" clip-rule="evenodd"
122
+ d="M11.4697 2.46967C11.7626 2.17678 12.2374 2.17678 12.5303 2.46967L17.0303 6.96967C17.3232 7.26256 17.3232 7.73744 17.0303 8.03033C16.7374 8.32322 16.2626 8.32322 15.9697 8.03033L12.75 4.81066L12.75 16.5C12.75 16.9142 12.4142 17.25 12 17.25C11.5858 17.25 11.25 16.9142 11.25 16.5L11.25 4.81066L8.03033 8.03033C7.73744 8.32322 7.26256 8.32322 6.96967 8.03033C6.67678 7.73744 6.67678 7.26256 6.96967 6.96967L11.4697 2.46967ZM3 15.75C3.41421 15.75 3.75 16.0858 3.75 16.5V18.75C3.75 19.5784 4.42157 20.25 5.25 20.25H18.75C19.5784 20.25 20.25 19.5784 20.25 18.75V16.5C20.25 16.0858 20.5858 15.75 21 15.75C21.4142 15.75 21.75 16.0858 21.75 16.5V18.75C21.75 20.4069 20.4069 21.75 18.75 21.75H5.25C3.59315 21.75 2.25 20.4069 2.25 18.75V16.5C2.25 16.0858 2.58579 15.75 3 15.75Z"
123
+ fill="#0F172A" />
124
+ </svg><input class="hidden" :name="'cfile_' + column" type="file"
125
+ @change="fileUpdated(column, $event)"></label>
126
+ </div>
127
+ </label>
128
+
129
+ <!-- КНОПКИ СОХРАНЕНИЯ-->
130
+ <div class="flex w-full mt-3 mb-2 justify-between items-center">
131
+ <div v-show="$props.opts?.Add.can"
132
+ class="cursor-pointer ml-2 text-lg py-2 text-white block bg-gray-400 font-medium rounded text-sm px-4 text-center hover:bg-blue-700 focus:ring-4 focus:ring-blue-200 dark:focus:ring-blue-900"
133
+ @click="Table.OpenedRow = null; FlameTableModal?.close()">
134
+ Отмена
135
+ </div>
136
+ <div
137
+ class="cursor-pointer ml-2 text-lg py-2 mr-3 text-white block bg-blue-600 font-medium rounded text-sm px-4 text-center hover:bg-blue-700 focus:ring-4 focus:ring-blue-200 dark:focus:ring-blue-900"
138
+ @click="SaveTable()">
139
+ {{ Table.mode === 'add' ? 'Добавить' : 'Сохранить' }}
140
+ </div>
141
+ </div>
142
+ </div>
143
+ </template>
144
+ </ModalVue>
64
145
  </template>
65
146
 
66
147
  <script lang="ts">
@@ -98,6 +179,7 @@ export default defineComponent({
98
179
  type: Function
99
180
  },
100
181
  },
182
+
101
183
  setup(props) {
102
184
 
103
185
  const Table = new FlameTable(props.model as any, props.opts);
@@ -162,6 +244,23 @@ export default defineComponent({
162
244
  }
163
245
  }
164
246
 
247
+ const fileUpdated = async (column: any, ev: any) => {
248
+ Table.columns[column].Popup.model = ev;
249
+ const prepared = (await REST.prepare({ myParam: ev })).myParam;
250
+ Table.columns[column].Popup.model = prepared
251
+ }
252
+
253
+ /*
254
+ const fileGetData = (model: any) => {
255
+ return computed(r => {
256
+ if (model instanceof Array && model.length > 0) {
257
+ if (typeof model[0].data === 'string') return model[0].data;
258
+ if (typeof model[0].file === 'string') return model[0].file;
259
+ }
260
+ return "";
261
+ })
262
+ }*/
263
+
165
264
  const getSelector = (arr: any, selectorKey: any, selectorVal: any) => {
166
265
  if (Array.isArray(arr)) return [selectorVal, selectorVal];
167
266
  // TODO: тут загрузка объекта должна быть
@@ -186,10 +285,22 @@ export default defineComponent({
186
285
  edit,
187
286
  SaveTable,
188
287
  deleteRow,
288
+ fileUpdated,
189
289
  getSelector
190
290
  }
191
291
 
192
292
  },
293
+ methods: {
294
+ fileGetData(thisArr: any) {
295
+
296
+ if (thisArr instanceof Array && thisArr.length > 0) {
297
+ if (typeof thisArr[0].data === 'string') return thisArr[0].data;
298
+ if (typeof thisArr[0].file === 'string') return thisArr[0].file;
299
+ }
300
+ return "";
301
+
302
+ }
303
+ },
193
304
 
194
305
  })
195
306
 
@@ -15,6 +15,12 @@ export default class TableOpts {
15
15
  */
16
16
  public columnsOpts: { [key: string]: IColumn } = {};
17
17
 
18
+ /**
19
+ * Параметры прогрузки
20
+ */
21
+ public LoadParams = {} as any;
22
+
23
+
18
24
  public set(ColumnName: string, mergingOpts: IColumn) {
19
25
  // TODO: ЕСТЬ ОШИБКА???
20
26
  if (this.columnsOpts[ColumnName] === undefined) this.columnsOpts[ColumnName] = new Column as any