123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154 |
- <template>
- <div>
- <div
- class="table-outer-container"
- @mousemove="columnResizing($event)"
- @touchmove="columnResizing($event)"
- >
- <div class="table-header">
- <div>
- <tippy
- v-if="filters.length > 0"
- :touch="true"
- :interactive="true"
- placement="bottom-start"
- theme="search"
- ref="search"
- trigger="click"
- @show="
- () => {
- showFiltersDropdown = true;
- }
- "
- @hide="
- () => {
- showFiltersDropdown = false;
- }
- "
- >
- <div class="control has-addons" ref="trigger">
- <button class="button is-primary">
- <i class="material-icons icon-with-button"
- >filter_list</i
- >
- Filters
- </button>
- <button class="button">
- <i class="material-icons">
- {{
- showFiltersDropdown
- ? "expand_more"
- : "expand_less"
- }}
- </i>
- </button>
- </div>
- <template #content>
- <div class="control is-grouped input-with-button">
- <p class="control select is-expanded">
- <select v-model="addFilterValue">
- <option
- v-for="type in filters"
- :key="type.name"
- :value="type"
- >
- {{ type.displayName }}
- </option>
- </select>
- </p>
- <p class="control">
- <button
- :disabled="!addFilterValue"
- class="button material-icons is-success"
- @click="addFilterItem()"
- >
- control_point
- </button>
- </p>
- </div>
- <div
- v-for="(filter, index) in editingFilters"
- :key="`filter-${index}`"
- class="
- advanced-filter
- control
- is-grouped is-expanded
- "
- >
- <div class="control select">
- <select
- v-model="filter.filter"
- @change="changeFilterType(index)"
- >
- <option
- v-for="type in filters"
- :key="type.name"
- :value="type"
- >
- {{ type.displayName }}
- </option>
- </select>
- </div>
- <div class="control select">
- <select
- v-model="filter.filterType"
- :disabled="!filter.filterType"
- >
- <option
- v-for="filterType in filterTypes(
- filter.filter
- )"
- :key="filterType.name"
- :value="filterType"
- :selected="
- filter.filter
- .defaultFilterType ===
- filterType.name
- "
- >
- {{ filterType.displayName }}
- </option>
- </select>
- </div>
- <div
- v-if="
- filter.filterType.name &&
- filter.filterType.name === 'exact' &&
- filter.filter.filterValues
- "
- class="control is-expanded select"
- >
- <select
- v-model="filter.data"
- :disabled="!filter.filterType"
- >
- <option
- v-for="filterValue in filter.filter
- .filterValues"
- :key="filterValue"
- :value="filterValue"
- >
- {{ filterValue }}
- </option>
- </select>
- </div>
- <div
- v-else-if="
- filter.filterType.name &&
- filter.filterType.name === 'boolean'
- "
- class="control is-expanded select"
- >
- <select
- v-model="filter.data"
- :disabled="!filter.filterType"
- >
- <option :value="true">true</option>
- <option :value="false">false</option>
- </select>
- </div>
- <div v-else class="control is-expanded">
- <input
- v-if="
- filter.filterType.name &&
- filter.filterType.name.startsWith(
- 'datetime'
- )
- "
- v-model="filter.data"
- class="input"
- type="datetime-local"
- />
- <input
- v-else-if="
- filter.filterType.name &&
- filter.filterType.name.startsWith(
- 'number'
- )
- "
- v-model="filter.data"
- class="input"
- type="number"
- :disabled="!filter.filterType"
- @keydown.enter="applyFilterAndGetData()"
- />
- <input
- v-else
- v-model="filter.data"
- class="input"
- type="text"
- placeholder="Search value"
- :disabled="!filter.filterType"
- @keydown.enter="applyFilterAndGetData()"
- @blur="blurFilterInput(filter)"
- @focus="focusFilterInput(filter)"
- @keydown="keydownFilterInput(filter)"
- />
- <div
- class="autosuggest-container"
- v-if="
- filter.filter.autosuggest &&
- (autosuggest.inputFocussed[
- filter.filter.name
- ] ||
- autosuggest.containerFocussed[
- filter.filter.name
- ]) &&
- autosuggest.items[
- filter.filter.name
- ]?.length > 0
- "
- @mouseover="
- focusFilterAutosuggestContainer(
- filter
- )
- "
- @mouseleave="
- blurFilterAutosuggestContainer(
- filter
- )
- "
- >
- <span
- class="autosuggest-item"
- tabindex="0"
- @click="
- selectAutosuggestItem(
- index,
- filter,
- item
- )
- "
- v-for="item in autosuggest.items[
- filter.filter.name
- ]"
- :key="item"
- >{{ item }}
- </span>
- </div>
- </div>
- <div class="control">
- <button
- class="button material-icons is-danger"
- @click="removeFilterItem(index)"
- >
- remove_circle_outline
- </button>
- </div>
- </div>
- <div
- v-if="editingFilters.length > 0"
- class="control is-expanded is-grouped"
- >
- <label class="control label"
- >Filter operator</label
- >
- <div class="control select is-expanded">
- <select v-model="filterOperator">
- <option
- v-for="operator in filterOperators"
- :key="operator.name"
- :value="operator.name"
- >
- {{ operator.displayName }}
- </option>
- </select>
- </div>
- </div>
- <div
- class="advanced-filter-bottom"
- v-if="editingFilters.length > 0"
- >
- <div class="control is-expanded">
- <button
- class="button is-info"
- @click="applyFilterAndGetData()"
- >
- <i
- class="
- material-icons
- icon-with-button
- "
- >filter_list</i
- >
- Apply filters
- </button>
- </div>
- </div>
- <div
- class="advanced-filter-bottom"
- v-else-if="editingFilters.length === 0"
- >
- <div class="control is-expanded">
- <button
- class="button is-info"
- @click="applyFilterAndGetData()"
- >
- <i
- class="
- material-icons
- icon-with-button
- "
- >filter_list</i
- >
- Apply filters
- </button>
- </div>
- </div>
- </template>
- </tippy>
- <tippy
- v-if="appliedFilters.length > 0"
- :touch="true"
- :interactive="true"
- theme="info"
- ref="activeFilters"
- >
- <div class="filters-indicator">
- {{ appliedFilters.length }}
- <i class="material-icons" @click.prevent="true"
- >filter_list</i
- >
- </div>
- <template #content>
- <p
- v-for="(filter, index) in appliedFilters"
- :key="`filter-${index}`"
- >
- {{ filter.filter.displayName }}
- {{
- appliedFilters.length === 1 &&
- appliedFilterOperator === "nor"
- ? "not"
- : ""
- }}
- {{
- filter.filterType.displayName.toLowerCase()
- }}
- "{{ filter.data }}"
- {{
- appliedFilters.length === index + 1
- ? ""
- : appliedFilterOperator
- }}
- </p>
- </template>
- </tippy>
- <i
- v-else
- class="filters-indicator material-icons"
- content="No active filters"
- v-tippy="{ theme: 'info' }"
- >
- filter_list_off
- </i>
- </div>
- <div>
- <tippy
- v-if="hidableSortedColumns.length > 0"
- :touch="true"
- :interactive="true"
- placement="bottom-end"
- theme="dropdown"
- ref="editColumns"
- trigger="click"
- @show="
- () => {
- showColumnsDropdown = true;
- }
- "
- @hide="
- () => {
- showColumnsDropdown = false;
- }
- "
- >
- <div class="control has-addons" ref="trigger">
- <button class="button is-primary">
- <i class="material-icons icon-with-button"
- >tune</i
- >
- Columns
- </button>
- <button class="button">
- <i class="material-icons">
- {{
- showColumnsDropdown
- ? "expand_more"
- : "expand_less"
- }}
- </i>
- </button>
- </div>
- <template #content>
- <draggable
- item-key="name"
- v-model="orderedColumns"
- v-bind="columnDragOptions"
- tag="div"
- draggable=".item-draggable"
- class="nav-dropdown-items"
- @change="columnOrderChanged"
- >
- <template #item="{ element: column }">
- <button
- v-if="
- column.name !== 'select' &&
- column.name !== 'placeholder'
- "
- :class="{
- sortable: column.sortable,
- 'item-draggable': column.draggable,
- 'nav-item': true
- }"
- @click.prevent="
- toggleColumnVisibility(column)
- "
- >
- <p
- class="
- control
- is-expanded
- checkbox-control
- "
- >
- <label class="switch">
- <input
- type="checkbox"
- :id="index"
- :checked="
- shownColumns.indexOf(
- column.name
- ) !== -1
- "
- @click="
- toggleColumnVisibility(
- column
- )
- "
- />
- <span
- :class="{
- slider: true,
- round: true,
- disabled:
- !column.hidable
- }"
- ></span>
- </label>
- <label :for="index">
- <span></span>
- <p>{{ column.displayName }}</p>
- </label>
- </p>
- </button>
- </template>
- </draggable>
- </template>
- </tippy>
- </div>
- </div>
- <div class="table-container">
- <table
- :class="{
- table: true,
- 'has-checkboxes': hasCheckboxes
- }"
- >
- <thead>
- <draggable
- item-key="name"
- v-model="orderedColumns"
- v-bind="columnDragOptions"
- tag="tr"
- handle=".handle"
- draggable=".item-draggable"
- @change="columnOrderChanged"
- >
- <template #item="{ element: column }">
- <th
- v-if="
- !(
- column.name === 'select' &&
- rows.length === 0
- ) &&
- shownColumns.indexOf(column.name) !== -1
- "
- :class="{
- sortable: column.sortable,
- 'item-draggable': column.draggable
- }"
- :style="{
- minWidth: Number.isNaN(column.minWidth)
- ? column.minWidth
- : `${column.minWidth}px`,
- width: Number.isNaN(column.width)
- ? column.width
- : `${column.width}px`,
- maxWidth: Number.isNaN(column.maxWidth)
- ? column.maxWidth
- : `${column.maxWidth}px`
- }"
- >
- <div v-if="column.name === 'select'">
- <p class="checkbox">
- <input
- type="checkbox"
- :checked="
- rows.filter(
- row => !row.removed
- ).length ===
- selectedRows.length
- "
- @click="toggleAllRows()"
- />
- </p>
- </div>
- <div v-else class="handle">
- <span>
- {{ column.displayName }}
- </span>
- <span
- v-if="column.sortable"
- :content="`Sort by ${column.displayName}`"
- v-tippy
- >
- <span
- v-if="
- !sort[column.sortProperty]
- "
- class="material-icons"
- @click="changeSort(column)"
- >
- unfold_more
- </span>
- <span
- v-if="
- sort[
- column.sortProperty
- ] === 'ascending'
- "
- class="material-icons active"
- @click="changeSort(column)"
- >
- expand_more
- </span>
- <span
- v-if="
- sort[
- column.sortProperty
- ] === 'descending'
- "
- class="material-icons active"
- @click="changeSort(column)"
- >
- expand_less
- </span>
- </span>
- </div>
- <div
- class="resizer"
- v-if="column.resizable"
- @mousedown.prevent.stop="
- columnResizingStart(column, $event)
- "
- @touchstart.prevent.stop="
- columnResizingStart(column, $event)
- "
- @mouseup="columnResizingStop()"
- @touchend="columnResizingStop()"
- @dblclick="columnResetWidth(column)"
- ></div>
- </th>
- </template>
- </draggable>
- </thead>
- <tbody>
- <tr
- v-for="(item, itemIndex) in rows"
- :key="item._id"
- :class="{
- selected: item.selected,
- highlighted: item.highlighted,
- updated: item.updated,
- removed: item.removed
- }"
- >
- <td
- v-for="column in sortedFilteredColumns"
- :key="`${item._id}-${column.name}`"
- >
- <slot
- :name="`column-${column.name}`"
- :item="item"
- v-if="
- column.properties.length === 0 ||
- column.properties.every(property =>
- property
- .split('.')
- .reduce(
- (previous, current) =>
- (previous !== null &&
- previous[
- current
- ]) !== null || null,
- item
- )
- )
- "
- ></slot>
- <p
- class="checkbox"
- v-if="column.name === 'select'"
- >
- <input
- type="checkbox"
- :checked="item.selected"
- @click="
- toggleSelectedRow(itemIndex, $event)
- "
- :disabled="item.removed"
- />
- </p>
- <span
- v-if="item.removed"
- class="removed-overlay"
- content="Item removed"
- v-tippy="{ theme: 'info' }"
- ></span>
- <div
- class="resizer"
- v-if="column.resizable"
- @mousedown.prevent.stop="
- columnResizingStart(column, $event)
- "
- @touchstart.prevent.stop="
- columnResizingStart(column, $event)
- "
- @mouseup="columnResizingStop()"
- @touchend="columnResizingStop()"
- @dblclick="columnResetWidth(column)"
- ></div>
- </td>
- </tr>
- </tbody>
- </table>
- </div>
- <div class="table-footer">
- <div class="page-controls">
- <button
- :class="{ disabled: page === 1 }"
- class="button is-primary material-icons"
- :disabled="page === 1"
- @click="changePage(1)"
- content="First Page"
- v-tippy
- >
- skip_previous
- </button>
- <button
- :class="{ disabled: page === 1 }"
- class="button is-primary material-icons"
- :disabled="page === 1"
- @click="changePage(page - 1)"
- content="Previous Page"
- v-tippy
- >
- fast_rewind
- </button>
- <p>Page {{ page }} / {{ lastPage }}</p>
- <button
- :class="{ disabled: page === lastPage }"
- class="button is-primary material-icons"
- :disabled="page === lastPage"
- @click="changePage(page + 1)"
- content="Next Page"
- v-tippy
- >
- fast_forward
- </button>
- <button
- :class="{ disabled: page === lastPage }"
- class="button is-primary material-icons"
- :disabled="page === lastPage"
- @click="changePage(lastPage)"
- content="Last Page"
- v-tippy
- >
- skip_next
- </button>
- </div>
- <div class="page-size">
- <div class="control">
- <label class="label">Items per page</label>
- <p class="control select">
- <select
- v-model.number="pageSize"
- @change="changePageSize()"
- >
- <option value="10">10</option>
- <option value="25">25</option>
- <option value="50">50</option>
- <option value="100">100</option>
- <option value="250">250</option>
- <option value="500">500</option>
- <option value="1000">1000</option>
- </select>
- </p>
- </div>
- </div>
- </div>
- </div>
- <div
- v-if="hasCheckboxes && selectedRows.length > 0"
- class="bulk-popup"
- :style="{
- top: bulkPopup.top + 'px',
- left: bulkPopup.left + 'px'
- }"
- >
- <button
- class="button is-primary"
- :content="
- selectedRows.length === 1
- ? `${selectedRows.length} row selected`
- : `${selectedRows.length} rows selected`
- "
- v-tippy="{ theme: 'info' }"
- >
- {{ selectedRows.length }}
- </button>
- <slot name="bulk-actions" :item="selectedRows" />
- <div class="right">
- <slot name="bulk-actions-right" :item="selectedRows" />
- <span
- class="material-icons drag-icon"
- @mousedown.left="onDragBox"
- @touchstart="onDragBox"
- @dblclick="resetBulkActionsPosition()"
- >
- drag_indicator
- </span>
- </div>
- </div>
- </div>
- </template>
- <script>
- import { mapGetters } from "vuex";
- import draggable from "vuedraggable";
- import Toast from "toasters";
- import ws from "@/ws";
- export default {
- components: {
- draggable
- },
- props: {
- /*
- Column properties:
- name: Unique lowercase name
- displayName: Nice name for the column header
- properties: The properties this column needs to show data
- sortable: Boolean for whether the order of a particular column can be changed
- sortProperty: The property the backend will sort on if this column gets sorted, e.g. title
- hidable: Boolean for whether a column can be hidden
- defaultVisibility: Default visibility for a column, either "shown" or "hidden"
- draggable: Boolean for whether a column can be dragged/reordered,
- resizable: Boolean for whether a column can be resized
- minWidth: Minimum width of column, e.g. 50px
- width: Width of column, e.g. 100px
- maxWidth: Maximum width of column, e.g. 150px
- */
- columnDefault: { type: Object, default: () => {} },
- columns: { type: Array, default: null },
- filters: { type: Array, default: null },
- dataAction: { type: String, default: null },
- name: { type: String, default: null },
- maxWidth: { type: Number, default: 1880 },
- query: { type: Boolean, default: true },
- events: { type: Object, default: () => {} }
- },
- data() {
- return {
- page: 1,
- pageSize: 10,
- rows: [],
- count: 0, // TODO Rename
- sort: {},
- orderedColumns: [],
- shownColumns: [],
- columnDragOptions() {
- return {
- animation: 200,
- group: "columns",
- disabled: false,
- ghostClass: "draggable-list-ghost",
- filter: ".ignore-elements",
- fallbackTolerance: 50
- };
- },
- editingFilters: [],
- appliedFilters: [],
- filterOperator: "or",
- appliedFilterOperator: "or",
- filterOperators: [
- {
- name: "or",
- displayName: "OR"
- },
- {
- name: "and",
- displayName: "AND"
- },
- {
- name: "nor",
- displayName: "NOR"
- }
- ],
- resizing: {},
- allFilterTypes: {
- contains: {
- name: "contains",
- displayName: "Contains"
- },
- exact: {
- name: "exact",
- displayName: "Exact"
- },
- regex: {
- name: "regex",
- displayName: "Regex"
- },
- datetimeBefore: {
- name: "datetimeBefore",
- displayName: "Before"
- },
- datetimeAfter: {
- name: "datetimeAfter",
- displayName: "After"
- },
- numberLesserEqual: {
- name: "numberLesserEqual",
- displayName: "<="
- },
- numberLesser: {
- name: "numberLesser",
- displayName: "<"
- },
- numberGreater: {
- name: "numberGreater",
- displayName: ">"
- },
- numberGreaterEqual: {
- name: "numberGreaterEqual",
- displayName: ">="
- },
- numberEquals: {
- name: "numberEquals",
- displayName: "=="
- },
- boolean: {
- name: "boolean",
- displayName: "Boolean"
- }
- },
- bulkPopup: {
- top: 0,
- left: 0,
- pos1: 0,
- pos2: 0,
- pos3: 0,
- pos4: 0
- },
- addFilterValue: null,
- showFiltersDropdown: false,
- showColumnsDropdown: false,
- lastColumnResizerTapped: null,
- lastColumnResizerTappedDate: 0,
- lastBulkActionsTappedDate: 0,
- autosuggest: {
- inputFocussed: {},
- containerFocussed: {},
- keydownInputTimeout: {},
- items: {},
- allItems: {
- genres: ["edm", "pop", "test"]
- }
- }
- };
- },
- computed: {
- properties() {
- return Array.from(
- new Set(
- this.sortedFilteredColumns.flatMap(
- column => column.properties
- )
- )
- );
- },
- lastPage() {
- return Math.ceil(this.count / this.pageSize);
- },
- sortedFilteredColumns() {
- return this.orderedColumns.filter(
- column => this.shownColumns.indexOf(column.name) !== -1
- );
- },
- hidableSortedColumns() {
- return this.orderedColumns.filter(column => column.hidable);
- },
- lastSelectedItemIndex() {
- return this.rows.findIndex(item => item.highlighted);
- },
- selectedRows() {
- return this.rows.filter(row => row.selected);
- },
- hasCheckboxes() {
- return (
- this.$slots["bulk-actions"] != null ||
- this.$slots["bulk-actions-right"] != null
- );
- },
- ...mapGetters({
- socket: "websockets/getSocket"
- })
- },
- watch: {
- selectedRows(newSelectedRows, oldSelectedRows) {
- // If selected rows goes from zero to one or more selected, trigger onWindowResize, as otherwise the popup could be out of bounds
- if (oldSelectedRows.length === 0 && newSelectedRows.length > 0)
- this.onWindowResize();
- }
- },
- mounted() {
- const tableSettings = this.getTableSettings();
- this.orderedColumns = [
- {
- name: "select",
- displayName: "",
- properties: [],
- sortable: false,
- hidable: false,
- draggable: false,
- resizable: false,
- minWidth: 47,
- defaultWidth: 47,
- maxWidth: 47
- },
- ...this.columns.map(column => ({
- ...this.columnDefault,
- ...column
- })),
- {
- name: "placeholder",
- displayName: "",
- properties: [],
- sortable: false,
- hidable: false,
- draggable: false,
- resizable: false,
- minWidth: "auto",
- width: "auto",
- maxWidth: "auto"
- }
- ].sort((columnA, columnB) => {
- // Always places select column in the first position
- if (columnA.name === "select") return -1;
- // Always places placeholder column in the last position
- if (columnB.name === "placeholder") return -1;
- // If there are no table settings stored, use default ordering
- if (!tableSettings || !tableSettings.columnOrder) return 0;
- const indexA = tableSettings.columnOrder.indexOf(columnA.name);
- const indexB = tableSettings.columnOrder.indexOf(columnB.name);
- // If either of the columns is not stored in the table settings, use default ordering
- if (indexA === -1 || indexB === -1) return 0;
- return indexA - indexB;
- });
- this.shownColumns = this.orderedColumns
- .filter(column => {
- // If table settings exist, use shownColumns from settings to determine which columns to show
- if (tableSettings && tableSettings.shownColumns)
- return (
- tableSettings.shownColumns.indexOf(column.name) !== -1
- );
- // Table settings don't exist, only show if the default visibility isn't hidden
- return column.defaultVisibility !== "hidden";
- })
- .map(column => column.name);
- this.recalculateWidths();
- if (tableSettings) {
- // If table settings' page is an integer, use it for the page
- if (Number.isInteger(tableSettings?.page))
- this.page = tableSettings.page;
- // If table settings' pageSize is an integer, use it for the pageSize
- if (Number.isInteger(tableSettings?.pageSize))
- this.pageSize = tableSettings.pageSize;
- // If table settings' columnSort exists, sort all still existing columns based on table settings' columnSort object
- if (tableSettings.columnSort) {
- Object.entries(tableSettings.columnSort).forEach(
- ([columnName, sortDirection]) => {
- if (
- this.columns.find(
- column => column.name === columnName
- )
- )
- this.sort[columnName] = sortDirection;
- }
- );
- }
- // If table settings' columnWidths exists, load the stored widths into the columns
- if (tableSettings.columnWidths) {
- this.orderedColumns = this.orderedColumns.map(orderedColumn => {
- const columnWidth = tableSettings.columnWidths.find(
- column => column.name === orderedColumn.name
- )?.width;
- if (columnWidth)
- return { ...orderedColumn, width: columnWidth };
- return orderedColumn;
- });
- }
- if (
- tableSettings.filter &&
- tableSettings.filter.appliedFilters &&
- tableSettings.filter.appliedFilterOperator
- ) {
- const { appliedFilters, appliedFilterOperator } =
- tableSettings.filter;
- // Set the applied filter operator and filter operator to the value stored in table settings
- this.appliedFilterOperator = this.filterOperator =
- appliedFilterOperator;
- // Set the applied filters and editing filters to the value stored in table settings, for all filters that are allowed
- this.appliedFilters = appliedFilters.filter(appliedFilter =>
- this.filters.find(
- filter => appliedFilter.filter.name === filter.name
- )
- );
- this.editingFilters = appliedFilters.filter(appliedFilter =>
- this.filters.find(
- filter => appliedFilter.filter.name === filter.name
- )
- );
- }
- }
- this.resetBulkActionsPosition();
- this.$nextTick(() => {
- this.onWindowResize();
- window.addEventListener("resize", this.onWindowResize);
- });
- ws.onConnect(this.init);
- if (this.events && this.events.updated)
- this.socket.on(`event:${this.events.updated.event}`, res => {
- const index = this.rows
- .map(row => row._id)
- .indexOf(
- this.events.updated.id
- .split(".")
- .reduce(
- (previous, current) =>
- (previous !== null &&
- previous[current] !== null) ||
- null,
- res.data
- )
- );
- const row = this.events.updated.item
- .split(".")
- .reduce(
- (previous, current) =>
- (previous !== null && previous[current] !== null) ||
- null,
- res.data
- );
- this.updateData(index, row);
- });
- if (this.events && this.events.removed)
- this.socket.on(`event:${this.events.removed.event}`, res => {
- const index = this.rows
- .map(row => row._id)
- .indexOf(
- this.events.removed.id
- .split(".")
- .reduce(
- (previous, current) =>
- (previous !== null &&
- previous[current] !== null) ||
- null,
- res.data
- )
- );
- this.removeData(index);
- });
- },
- unmounted() {
- window.removeEventListener("resize", this.onWindowResize);
- if (this.storeTableSettingsDebounceTimeout)
- clearTimeout(this.storeTableSettingsDebounceTimeout);
- },
- methods: {
- init() {
- this.getData();
- if (this.query) this.setQuery();
- if (this.events) {
- if (this.events.room)
- this.socket.dispatch(
- "apis.joinRoom",
- this.events.room,
- () => {}
- );
- if (this.events.adminRoom)
- this.socket.dispatch(
- "apis.joinAdminRoom",
- this.events.adminRoom,
- () => {}
- );
- }
- this.filters.forEach(filter => {
- if (filter.autosuggest && filter.autosuggestDataAction) {
- this.socket.dispatch(filter.autosuggestDataAction, res => {
- if (res.status === "success") {
- const { items } = res.data;
- this.autosuggest.allItems[filter.name] = items;
- } else {
- new Toast(res.message);
- }
- });
- }
- });
- },
- getData() {
- this.socket.dispatch(
- this.dataAction,
- this.page,
- this.pageSize,
- this.properties,
- this.sort,
- this.appliedFilters.map(filter => ({
- ...filter,
- filterType: filter.filterType.name
- })),
- this.appliedFilterOperator,
- res => {
- console.log(111, res);
- if (res.status === "success") {
- const { data, count } = res.data;
- this.rows = data.map(row => ({
- ...row,
- selected: false
- }));
- this.count = count;
- } else {
- new Toast(res.message);
- }
- }
- );
- },
- changePageSize() {
- this.page = 1;
- this.getData();
- this.storeTableSettings();
- },
- changePage(page) {
- if (page < 1) return;
- if (page > this.lastPage) return;
- if (page === this.page) return;
- this.page = page;
- this.getData();
- if (this.query) this.setQuery();
- },
- changeSort(column) {
- if (column.sortable) {
- const { sortProperty } = column;
- if (this.sort[sortProperty] === undefined)
- this.sort[sortProperty] = "ascending";
- else if (this.sort[sortProperty] === "ascending")
- this.sort[sortProperty] = "descending";
- else if (this.sort[sortProperty] === "descending")
- delete this.sort[sortProperty];
- this.getData();
- this.storeTableSettings();
- }
- },
- toggleColumnVisibility(column) {
- if (!column.hidable) return false;
- if (this.shownColumns.indexOf(column.name) !== -1) {
- if (this.shownColumns.length <= 3)
- return new Toast(
- `Unable to hide column ${column.displayName}, there must be at least 1 visibile column`
- );
- this.shownColumns.splice(
- this.shownColumns.indexOf(column.name),
- 1
- );
- } else {
- this.shownColumns.push(column.name);
- }
- this.recalculateWidths();
- this.getData();
- return this.storeTableSettings();
- },
- toggleSelectedRow(itemIndex, event) {
- const { shiftKey, ctrlKey } = event;
- // Shift was pressed, so attempt to select all items between the clicked item and last clicked item
- if (shiftKey) {
- // If the clicked item is already selected, prevent default, otherwise the checkbox will be unchecked
- if (this.rows[itemIndex].selected) event.preventDefault();
- // If there is a last clicked item
- if (this.lastSelectedItemIndex >= 0) {
- // Clicked item is lower than last item, so select upwards until it reaches the last selected item
- if (itemIndex > this.lastSelectedItemIndex) {
- for (
- let itemIndexUp = itemIndex;
- itemIndexUp > this.lastSelectedItemIndex;
- itemIndexUp -= 1
- ) {
- this.rows[itemIndexUp].selected = true;
- }
- }
- // Clicked item is higher than last item, so select downwards until it reaches the last selected item
- else if (itemIndex < this.lastSelectedItemIndex) {
- for (
- let itemIndexDown = itemIndex;
- itemIndexDown < this.lastSelectedItemIndex;
- itemIndexDown += 1
- ) {
- this.rows[itemIndexDown].selected = true;
- }
- }
- }
- }
- // Ctrl was pressed, so attempt to unselect all items between the clicked item and last clicked item
- else if (ctrlKey) {
- // If the clicked item is already unselected, prevent default, otherwise the checkbox will be checked
- if (!this.rows[itemIndex].selected) event.preventDefault();
- // If there is a last clicked item
- if (this.lastSelectedItemIndex >= 0) {
- // Clicked item is lower than last item, so unselect upwards until it reaches the last selected item
- if (itemIndex > this.lastSelectedItemIndex) {
- for (
- let itemIndexUp = itemIndex;
- itemIndexUp >= this.lastSelectedItemIndex;
- itemIndexUp -= 1
- ) {
- this.rows[itemIndexUp].selected = false;
- }
- }
- // Clicked item is higher than last item, so unselect downwards until it reaches the last selected item
- else if (itemIndex < this.lastSelectedItemIndex) {
- for (
- let itemIndexDown = itemIndex;
- itemIndexDown <= this.lastSelectedItemIndex;
- itemIndexDown += 1
- ) {
- this.rows[itemIndexDown].selected = false;
- }
- }
- }
- }
- // Neither ctrl nor shift were pressed, so toggle clicked item
- else {
- this.rows[itemIndex].selected = !this.rows[itemIndex].selected;
- }
- // Set the last clicked item to no longer be highlighted, if it exists
- if (this.lastSelectedItemIndex >= 0)
- this.rows[this.lastSelectedItemIndex].highlighted = false;
- // Set the clicked item to be highlighted
- this.rows[itemIndex].highlighted = true;
- },
- toggleAllRows() {
- if (
- this.rows.filter(row => !row.removed).length >
- this.selectedRows.length
- ) {
- this.rows = this.rows.map(row => {
- if (row.removed) return row;
- return { ...row, selected: true };
- });
- } else {
- this.rows = this.rows.map(row => {
- if (row.removed) return row;
- return { ...row, selected: false };
- });
- }
- },
- addFilterItem() {
- this.editingFilters.push({
- data: "",
- filter: this.addFilterValue,
- filterType:
- this.allFilterTypes[this.addFilterValue.defaultFilterType]
- });
- },
- removeFilterItem(index) {
- this.editingFilters.splice(index, 1);
- },
- columnResizingStart(column, event) {
- const eventIsTouch = event.type === "touchstart";
- if (eventIsTouch) {
- // Handle double click from touch (if this method is called for the same column twice in a row within one second)
- if (
- this.lastColumnResizerTapped === column &&
- Date.now() - this.lastColumnResizerTappedDate <= 1000
- ) {
- this.columnResetWidth(column);
- this.lastColumnResizerTapped = null;
- this.lastColumnResizerTappedDate = 0;
- return;
- }
- this.lastColumnResizerTapped = column;
- this.lastColumnResizerTappedDate = Date.now();
- }
- this.resizing.resizing = true;
- this.resizing.resizingColumn = column;
- this.resizing.width = event.target.parentElement.offsetWidth;
- this.resizing.lastX = eventIsTouch
- ? event.targetTouches[0].clientX
- : event.x;
- },
- columnResizing(event) {
- if (this.resizing.resizing) {
- const eventIsTouch = event.type === "touchmove";
- if (!eventIsTouch && event.buttons !== 1) {
- this.resizing.resizing = false;
- this.storeTableSettings();
- }
- const x = eventIsTouch
- ? event.changedTouches[0].clientX
- : event.x;
- this.resizing.width -= this.resizing.lastX - x;
- this.resizing.lastX = x;
- if (
- this.resizing.resizingColumn.minWidth &&
- this.resizing.resizingColumn.maxWidth
- ) {
- this.resizing.resizingColumn.width = Math.max(
- Math.min(
- this.resizing.resizingColumn.maxWidth,
- this.resizing.width
- ),
- this.resizing.resizingColumn.minWidth
- );
- } else if (this.resizing.resizingColumn.minWidth) {
- this.resizing.resizingColumn.width = Math.max(
- this.resizing.width,
- this.resizing.resizingColumn.minWidth
- );
- } else if (this.resizing.resizingColumn.maxWidth) {
- this.resizing.resizingColumn.width = Math.min(
- this.resizing.resizingColumn.maxWidth,
- this.resizing.width
- );
- } else {
- this.resizing.resizingColumn.width = this.resizing.width;
- }
- this.resizing.width = this.resizing.resizingColumn.width;
- console.log(`New width: ${this.resizing.width}px`);
- this.storeTableSettings();
- }
- },
- columnResizingStop() {
- this.resizing.resizing = false;
- this.storeTableSettings();
- },
- columnResetWidth(column) {
- const index = this.orderedColumns.indexOf(column);
- if (column.defaultWidth && !Number.isNaN(column.defaultWidth))
- this.orderedColumns[index].width = column.defaultWidth;
- else if (
- column.calculatedWidth &&
- !Number.isNaN(column.calculatedWidth)
- )
- this.orderedColumns[index].width = column.calculatedWidth;
- this.storeTableSettings();
- },
- filterTypes(filter) {
- if (!filter || !filter.filterTypes) return [];
- return filter.filterTypes.map(
- filterType => this.allFilterTypes[filterType]
- );
- },
- changeFilterType(index) {
- this.editingFilters[index].filterType =
- this.allFilterTypes[
- this.editingFilters[index].filter.defaultFilterType
- ];
- },
- onDragBox(e) {
- const e1 = e || window.event;
- const e1IsTouch = e1.type === "touchstart";
- e1.preventDefault();
- if (e1IsTouch) {
- // Handle double click from touch (if this method is twice in a row within one second)
- if (Date.now() - this.lastBulkActionsTappedDate <= 1000) {
- this.resetBulkActionsPosition();
- this.lastBulkActionsTappedDate = 0;
- return;
- }
- this.lastBulkActionsTappedDate = Date.now();
- }
- this.bulkPopup.pos3 = e1IsTouch
- ? e1.changedTouches[0].clientX
- : e1.clientX;
- this.bulkPopup.pos4 = e1IsTouch
- ? e1.changedTouches[0].clientY
- : e1.clientY;
- document.onmousemove = document.ontouchmove = e => {
- const e2 = e || window.event;
- const e2IsTouch = e2.type === "touchmove";
- if (!e2IsTouch) e2.preventDefault();
- // Get the clientX and clientY
- const e2ClientX = e2IsTouch
- ? e2.changedTouches[0].clientX
- : e2.clientX;
- const e2ClientY = e2IsTouch
- ? e2.changedTouches[0].clientY
- : e2.clientY;
- // calculate the new cursor position:
- this.bulkPopup.pos1 = this.bulkPopup.pos3 - e2ClientX;
- this.bulkPopup.pos2 = this.bulkPopup.pos4 - e2ClientY;
- this.bulkPopup.pos3 = e2ClientX;
- this.bulkPopup.pos4 = e2ClientY;
- // set the element's new position:
- this.bulkPopup.top -= this.bulkPopup.pos2;
- this.bulkPopup.left -= this.bulkPopup.pos1;
- if (this.bulkPopup.top < 0) this.bulkPopup.top = 0;
- if (this.bulkPopup.top > document.body.clientHeight - 50)
- this.bulkPopup.top = document.body.clientHeight - 50;
- if (this.bulkPopup.left < 0) this.bulkPopup.left = 0;
- if (this.bulkPopup.left > document.body.clientWidth - 400)
- this.bulkPopup.left = document.body.clientWidth - 400;
- };
- document.onmouseup = document.ontouchend = () => {
- document.onmouseup = null;
- document.ontouchend = null;
- document.onmousemove = null;
- document.ontouchmove = null;
- };
- },
- resetBulkActionsPosition() {
- this.bulkPopup.top = document.body.clientHeight - 56;
- this.bulkPopup.left = document.body.clientWidth / 2 - 200;
- },
- applyFilterAndGetData() {
- this.appliedFilters = JSON.parse(
- JSON.stringify(this.editingFilters)
- );
- this.appliedFilterOperator = this.filterOperator;
- this.page = 1;
- this.getData();
- this.storeTableSettings();
- },
- recalculateWidths() {
- let noWidthCount = 0;
- let calculatedWidth = 0;
- this.orderedColumns.forEach(column => {
- if (
- this.shownColumns.indexOf(column.name) !== -1 &&
- (column.name !== "select" || this.hasCheckboxes)
- )
- if (
- Number.isFinite(column.width) &&
- !Number.isFinite(column.calculatedWidth)
- ) {
- calculatedWidth += column.width;
- } else if (Number.isFinite(column.defaultWidth)) {
- calculatedWidth += column.defaultWidth;
- } else {
- noWidthCount += 1;
- }
- });
- calculatedWidth = Math.floor(
- (Math.min(this.maxWidth, document.body.clientWidth) -
- calculatedWidth) /
- (noWidthCount - 1)
- );
- this.orderedColumns = this.orderedColumns.map(column => {
- const orderedColumn = column;
- if (this.shownColumns.indexOf(orderedColumn.name) !== -1) {
- let newWidth;
- if (Number.isFinite(orderedColumn.defaultWidth)) {
- newWidth = orderedColumn.defaultWidth;
- } else {
- // eslint-disable-next-line no-param-reassign
- newWidth = orderedColumn.calculatedWidth = Math.min(
- Math.max(
- orderedColumn.minWidth || 100, // fallback 100px min width
- calculatedWidth
- ),
- orderedColumn.maxWidth || 1000 // fallback 1000px max width
- );
- }
- if (newWidth && !Number.isFinite(orderedColumn.width))
- orderedColumn.width = newWidth;
- }
- return orderedColumn;
- });
- },
- columnOrderChanged() {
- this.storeTableSettings();
- },
- getTableSettings() {
- const urlTableSettings = {};
- if (this.query) {
- if (this.$route.query.page)
- urlTableSettings.page = Number.parseInt(
- this.$route.query.page
- );
- if (this.$route.query.pageSize)
- urlTableSettings.pageSize = Number.parseInt(
- this.$route.query.pageSize
- );
- if (this.$route.query.shownColumns)
- urlTableSettings.shownColumns = JSON.parse(
- this.$route.query.shownColumns
- );
- if (this.$route.query.columnOrder)
- urlTableSettings.columnOrder = JSON.parse(
- this.$route.query.columnOrder
- );
- if (this.$route.query.columnWidths)
- urlTableSettings.columnWidths = JSON.parse(
- this.$route.query.columnWidths
- );
- if (this.$route.query.columnSort)
- urlTableSettings.columnSort = JSON.parse(
- this.$route.query.columnSort
- );
- if (this.$route.query.filter)
- urlTableSettings.filter = JSON.parse(
- this.$route.query.filter
- );
- }
- const localStorageTableSettings = JSON.parse(
- localStorage.getItem(`advancedTableSettings:${this.name}`)
- );
- return {
- ...localStorageTableSettings,
- ...urlTableSettings
- };
- },
- storeTableSettings() {
- // Clear debounce timeout
- if (this.storeTableSettingsDebounceTimeout)
- clearTimeout(this.storeTableSettingsDebounceTimeout);
- // Resizing calls this function a lot, so rather than saving dozens of times a second, use debouncing
- this.storeTableSettingsDebounceTimeout = setTimeout(() => {
- if (this.query) this.setQuery();
- this.setLocalStorage();
- }, 250);
- },
- setQuery() {
- const queryObject = {
- ...this.$route.query,
- page: this.page,
- pageSize: this.pageSize,
- filter: JSON.stringify({
- appliedFilters: this.appliedFilters,
- appliedFilterOperator: this.appliedFilterOperator
- }),
- columnSort: JSON.stringify(this.sort),
- columnOrder: JSON.stringify(
- this.orderedColumns.map(column => column.name)
- ),
- columnWidths: JSON.stringify(
- this.orderedColumns.map(column => ({
- name: column.name,
- width: column.width
- }))
- ),
- shownColumns: JSON.stringify(this.shownColumns)
- };
- const queryString = `?${Object.keys(queryObject)
- .map(key => `${key}=${queryObject[key]}`)
- .join("&")}`;
- window.history.replaceState(null, null, queryString);
- },
- setLocalStorage() {
- localStorage.setItem(
- `advancedTableSettings:${this.name}`,
- JSON.stringify({
- pageSize: this.pageSize,
- filter: {
- appliedFilters: this.appliedFilters,
- appliedFilterOperator: this.appliedFilterOperator
- },
- columnSort: this.sort,
- columnOrder: this.orderedColumns.map(column => column.name),
- columnWidths: this.orderedColumns.map(column => ({
- name: column.name,
- width: column.width
- })),
- shownColumns: this.shownColumns
- })
- );
- },
- onWindowResize() {
- // Only change the position if the popup is actually visible
- if (this.selectedRows.length === 0) return;
- if (this.bulkPopup.top < 0) this.bulkPopup.top = 0;
- if (this.bulkPopup.top > document.body.clientHeight - 50)
- this.bulkPopup.top = document.body.clientHeight - 50;
- if (this.bulkPopup.left < 0) this.bulkPopup.left = 0;
- if (this.bulkPopup.left > document.body.clientWidth - 400)
- this.bulkPopup.left = document.body.clientWidth - 400;
- },
- updateData(index, data) {
- this.rows[index] = { ...this.rows[index], ...data, updated: true };
- },
- removeData(index) {
- this.rows[index] = {
- ...this.rows[index],
- selected: false,
- removed: true
- };
- },
- blurFilterInput(filter) {
- this.autosuggest.inputFocussed[filter.filter.name] = false;
- },
- focusFilterInput(filter) {
- this.autosuggest.inputFocussed[filter.filter.name] = true;
- },
- keydownFilterInput(filter) {
- const { name } = filter.filter;
- clearTimeout(this.autosuggest.keydownInputTimeout[name]);
- this.autosuggest.keydownInputTimeout[name] = setTimeout(() => {
- if (filter.data.length > 1) {
- this.autosuggest.items[name] = this.autosuggest.allItems[
- name
- ]?.filter(item =>
- item.toLowerCase().startsWith(filter.data.toLowerCase())
- );
- } else this.autosuggest.items[name] = [];
- }, 1000);
- },
- focusFilterAutosuggestContainer(filter) {
- this.autosuggest.containerFocussed[filter.filter.name] = true;
- },
- blurFilterAutosuggestContainer(filter) {
- this.autosuggest.containerFocussed[filter.filter.name] = false;
- },
- selectAutosuggestItem(index, filter, item) {
- this.editingFilters[index].data = item;
- this.autosuggest.items[filter.filter.name] = [];
- }
- }
- };
- </script>
- <style lang="scss" scoped>
- .night-mode {
- .table-outer-container {
- .table-container .table {
- &,
- thead th {
- background-color: var(--dark-grey-3);
- color: var(--light-grey-2);
- }
- tr {
- th,
- td {
- border-color: var(--dark-grey) !important;
- &:first-child {
- background-color: var(--dark-grey-3) !important;
- }
- }
- &:nth-child(even) {
- &,
- td:first-child {
- background-color: var(--dark-grey-2) !important;
- }
- }
- &:hover,
- &:focus,
- &.highlighted {
- th,
- td {
- &,
- &:first-child {
- background-color: var(--dark-grey-4) !important;
- }
- }
- }
- }
- }
- .table-header,
- .table-footer {
- background-color: var(--dark-grey-3);
- color: var(--light-grey-2);
- }
- .label.control {
- background-color: var(--dark-grey) !important;
- border-color: var(--grey-3) !important;
- color: var(--white) !important;
- }
- }
- .bulk-popup {
- border: 0;
- background-color: var(--dark-grey-2);
- color: var(--white);
- .material-icons {
- color: var(--white);
- }
- }
- .autosuggest-container {
- background-color: var(--dark-grey) !important;
- .autosuggest-item {
- background-color: var(--dark-grey) !important;
- color: var(--white) !important;
- border-color: var(--dark-grey) !important;
- }
- .autosuggest-item:hover,
- .autosuggest-item:focus {
- background-color: var(--dark-grey-2) !important;
- }
- }
- }
- .table-outer-container {
- border-radius: 5px;
- box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1);
- margin: 10px 0;
- overflow: hidden;
- .table-container {
- overflow-x: auto;
- table {
- border-collapse: separate;
- table-layout: fixed;
- thead {
- tr {
- th {
- height: 40px;
- line-height: 40px;
- border: 1px solid var(--light-grey-2);
- border-width: 1px 1px 1px 0;
- padding: 0;
- &:last-child {
- border-width: 1px 0 1px;
- }
- &.sortable {
- cursor: pointer;
- }
- & > div {
- display: flex;
- white-space: nowrap;
- padding: 8px 10px;
- & > span {
- margin-left: 5px;
- &:first-child {
- margin-left: 0;
- margin-right: auto;
- }
- & > .material-icons {
- font-size: 22px;
- position: relative;
- top: 6px;
- cursor: pointer;
- &.active {
- color: var(--primary-color);
- }
- &:hover,
- &:focus {
- filter: brightness(90%);
- }
- }
- }
- }
- }
- }
- }
- tbody {
- tr {
- &.highlighted {
- background-color: var(--light-grey);
- }
- td {
- border: 1px solid var(--light-grey-2);
- border-width: 0 1px 1px 0;
- &:last-child {
- border-width: 0 0 1px;
- }
- /deep/ .row-options {
- display: flex;
- justify-content: space-between;
- .icon-with-button {
- height: 30px;
- width: 30px;
- }
- }
- }
- &.removed {
- filter: grayscale(100%);
- cursor: not-allowed;
- user-select: none;
- td .removed-overlay {
- position: absolute;
- top: 0;
- left: 0;
- bottom: 0;
- right: 5px;
- z-index: 5;
- }
- }
- }
- }
- }
- table {
- thead tr,
- tbody tr {
- th,
- td {
- position: relative;
- white-space: nowrap;
- text-overflow: ellipsis;
- overflow: hidden;
- &:first-child {
- display: none;
- }
- .resizer {
- height: 100%;
- width: 5px;
- background-color: transparent;
- cursor: col-resize;
- position: absolute;
- right: 0;
- top: 0;
- }
- }
- &:nth-child(even) td:first-child {
- background-color: #fafafa;
- }
- &:hover,
- &:focus,
- &.highlighted {
- th,
- td {
- &,
- &:first-child {
- background-color: var(--light-grey);
- }
- }
- }
- }
- &.has-checkboxes {
- thead tr,
- tbody tr {
- th,
- td {
- &:first-child {
- display: table-cell;
- position: sticky;
- left: 0;
- background-color: var(--white);
- z-index: 2;
- }
- }
- }
- }
- }
- }
- .table-header,
- .table-footer {
- display: flex;
- flex-direction: row;
- flex-wrap: wrap;
- justify-content: space-between;
- line-height: 36px;
- background-color: var(--white);
- }
- .table-header > div {
- display: flex;
- flex-direction: row;
- > span > .control {
- margin: 5px;
- }
- .filters-indicator {
- line-height: 46px;
- display: flex;
- align-items: center;
- column-gap: 4px;
- }
- }
- .table-footer {
- .page-controls,
- .page-size > .control {
- display: flex;
- flex-direction: row;
- margin-bottom: 0 !important;
- button {
- margin: 5px;
- font-size: 20px;
- }
- p,
- label {
- margin: 5px;
- font-size: 14px;
- font-weight: 600;
- }
- &.select::after {
- top: 18px;
- }
- }
- }
- }
- .control.is-grouped {
- display: flex;
- & > .control {
- &.label {
- height: 36px;
- background-color: var(--white);
- border: 1px solid var(--light-grey-2);
- color: var(--dark-grey-2);
- appearance: none;
- border-radius: 3px;
- font-size: 14px;
- line-height: 34px;
- padding-left: 8px;
- padding-right: 8px;
- }
- &.select.is-expanded > select {
- width: 100%;
- }
- & > input,
- & > select,
- & > .button,
- &.label {
- border-radius: 0;
- }
- &:first-child {
- & > input,
- & > select,
- & > .button,
- &.label {
- border-radius: 5px 0 0 5px;
- }
- }
- &:last-child {
- & > input,
- & > select,
- & > .button,
- &.label {
- border-radius: 0 5px 5px 0;
- }
- }
- & > .button {
- font-size: 22px;
- }
- }
- @media screen and (max-width: 500px) {
- &.advanced-filter {
- flex-wrap: wrap;
- .control.select {
- width: 50%;
- select {
- width: 100%;
- }
- }
- .control {
- margin-bottom: 0 !important;
- &:nth-child(1) select {
- border-radius: 5px 0 0 0;
- }
- &:nth-child(2) select {
- border-radius: 0 5px 0 0;
- }
- &:nth-child(3) input {
- border-radius: 0 0 0 5px;
- }
- &:nth-child(4) button {
- border-radius: 0 0 5px 0;
- }
- }
- }
- }
- }
- .autosuggest-container {
- position: absolute;
- background: var(--white);
- width: calc(100% + 1px);
- top: 35px;
- z-index: 200;
- overflow: auto;
- max-height: 98px;
- clear: both;
- .autosuggest-item {
- padding: 8px;
- display: block;
- border: 1px solid var(--light-grey-2);
- margin-top: -1px;
- line-height: 16px;
- cursor: pointer;
- -webkit-user-select: none;
- -ms-user-select: none;
- -moz-user-select: none;
- user-select: none;
- }
- .autosuggest-item:hover,
- .autosuggest-item:focus {
- background-color: var(--light-grey);
- }
- .autosuggest-item:first-child {
- border-top: none;
- }
- .autosuggest-item:last-child {
- border-radius: 0 0 3px 3px;
- }
- }
- .advanced-filter {
- .control {
- position: relative;
- }
- }
- .advanced-filter-bottom {
- display: flex;
- .button {
- font-size: 16px !important;
- width: 100%;
- }
- .control {
- margin: 0 !important;
- }
- }
- /deep/ .bulk-popup {
- display: flex;
- position: fixed;
- flex-direction: row;
- width: 100%;
- max-width: 400px;
- line-height: 36px;
- z-index: 5;
- border: 1px solid var(--light-grey-3);
- border-radius: 5px;
- box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22);
- background-color: var(--white);
- color: var(--dark-grey);
- padding: 5px;
- .right {
- display: flex;
- flex-direction: row;
- margin-left: auto;
- }
- .drag-icon {
- position: relative;
- top: 6px;
- color: var(--dark-grey);
- cursor: move;
- }
- .bulk-actions {
- display: flex;
- flex-direction: row;
- width: 100%;
- justify-content: space-evenly;
- .material-icons {
- position: relative;
- top: 6px;
- margin-left: 5px;
- cursor: pointer;
- color: var(--primary-color);
- &:hover,
- &:focus {
- filter: brightness(90%);
- }
- }
- .delete-icon {
- color: var(--dark-red);
- }
- }
- }
- </style>
|