Add support for sharing table views via link

This commit is contained in:
Connor Cleveland
2023-10-21 21:05:31 -05:00
parent aa2e79b101
commit 2fccfc272f
18 changed files with 3559 additions and 3480 deletions

View File

@@ -27,7 +27,8 @@
"showArchived": "Zobrazit archivované",
"notAccessTitle": "Nemáte oprávnění k přístupu",
"hideColumns": "Skrýt sloupce",
"clearFilters": "Zrušit filtry"
"clearFilters": "Zrušit filtry",
"share": "sdílet"
},
"warnWhenUnsavedChanges": "Jste si jisti, že chcete odejít? Máte neuložené změny.",
"notifications": {

View File

@@ -23,7 +23,8 @@
"clone": "Duplizieren",
"notAccessTitle": "Keine Berechtigung, um hierauf zuzugreifen",
"hideColumns": "Spalten anpassen",
"clearFilters": "Filter leeren"
"clearFilters": "Filter leeren",
"share": "Teilen"
},
"warnWhenUnsavedChanges": "Sicher? Nicht gespeicherte Änderungen gehen verloren!",
"notifications": {

View File

@@ -27,7 +27,8 @@
"showArchived": "Show Archived",
"notAccessTitle": "You don't have permission to access",
"hideColumns": "Hide Columns",
"clearFilters": "Clear Filters"
"clearFilters": "Clear Filters",
"share": "Share"
},
"warnWhenUnsavedChanges": "Are you sure you want to leave? You have unsaved changes.",
"notifications": {

View File

@@ -27,7 +27,8 @@
"showArchived": "Mostrar Archivados",
"notAccessTitle": "No tienes permiso de acceso",
"hideColumns": "Ocultar Columnas",
"clearFilters": "Borrar filtros"
"clearFilters": "Borrar filtros",
"share": "compartir"
},
"warnWhenUnsavedChanges": "Seguro que quieres salir?. Hay cambios sin guardar.",
"notifications": {

View File

@@ -153,7 +153,8 @@
"clearFilters": "Effacer les filtres",
"unArchive": "Désarchiver",
"clone": "Cloner",
"clear": "Effacer"
"clear": "Effacer",
"share": "partager"
},
"filament": {
"fields_help": {

View File

@@ -152,7 +152,8 @@
"clearFilters": "Szűrők törlése",
"unArchive": "Arhiválás visszavonása",
"clone": "Másolás",
"clear": "Törlés"
"clear": "Törlés",
"share": "Ossza meg"
},
"filament": {
"fields_help": {

View File

@@ -152,7 +152,8 @@
"clearFilters": "Cancella Filtri",
"unArchive": "Ripristina",
"clone": "Clona",
"clear": "Pulisci"
"clear": "Pulisci",
"share": "condividere"
},
"filament": {
"fields_help": {

View File

@@ -20,7 +20,8 @@
"clear": "Tøm",
"filter": "Filtrer",
"refresh": "Gjenoppfrisk",
"notAccessTitle": "Du har ikke rettighet til å få tilgang"
"notAccessTitle": "Du har ikke rettighet til å få tilgang",
"share": "Andel"
},
"filament": {
"fields": {

View File

@@ -20,7 +20,8 @@
"clearFilters": "Filters leegmaken",
"unArchive": "Dearchiveren",
"clone": "Klonen",
"clear": "Wissen"
"clear": "Wissen",
"share": "delen"
},
"actions": {
"create": "Aanmaken",

View File

@@ -27,7 +27,8 @@
"showArchived": "Pokaż zarchiwizowane",
"notAccessTitle": "Nie masz zezwolenia na dostęp",
"hideColumns": "Edytuj kolumny",
"clearFilters": "Wyczyść filtry"
"clearFilters": "Wyczyść filtry",
"share": "udział"
},
"spool": {
"titles": {

View File

@@ -27,7 +27,8 @@
"showArchived": "Показать архивные",
"notAccessTitle": "У вас нет разрешения на доступ",
"hideColumns": "Скрыть столбцы",
"clearFilters": "Очистить фильтр"
"clearFilters": "Очистить фильтр",
"share": "делиться"
},
"warnWhenUnsavedChanges": "Вы уверены, что хотите выйти? У вас есть несохраненные изменения.",
"notifications": {

View File

@@ -27,7 +27,8 @@
"showArchived": "Visa arkiverade",
"notAccessTitle": "Du har inte tillgång till denna sida",
"hideColumns": "Dölj kolumner",
"clearFilters": "Rensa filter"
"clearFilters": "Rensa filter",
"share": "aktie"
},
"warnWhenUnsavedChanges": "Är du säker på att du vill lämna sidan? Du har osparade ändringar.",
"notifications": {

View File

@@ -20,7 +20,8 @@
"logout": "Вийти",
"notAccessTitle": "У Вас бракує прав для доступу",
"clone": "Клонувати",
"unArchive": "Розархівувати"
"unArchive": "Розархівувати",
"share": "частка"
},
"spool": {
"fields": {

View File

@@ -27,7 +27,8 @@
"showArchived": "显示存档",
"notAccessTitle": "您没有访问权限",
"hideColumns": "隐藏列",
"clearFilters": "清除筛选器"
"clearFilters": "清除筛选器",
"share": "分享"
},
"warnWhenUnsavedChanges": "您确定要离开吗?您有未保存的更改。",
"notifications": {

View File

@@ -5,8 +5,8 @@ import { Table, Space, Button, Dropdown } from "antd";
import dayjs from "dayjs";
import utc from "dayjs/plugin/utc";
import { IFilament } from "./model";
import { EditOutlined, FilterOutlined } from "@ant-design/icons";
import { TableState, useInitialTableState, useStoreInitialState } from "../../utils/saveload";
import { EditOutlined, FilterOutlined, ShareAltOutlined } from "@ant-design/icons";
import { TableState, shareSavedState, useInitialTableState, useStoreInitialState } from "../../utils/saveload";
import {
DateColumn,
FilteredQueryColumn,
@@ -164,6 +164,20 @@ export const FilamentList: React.FC<IResourceComponentsProps> = () => {
{t("buttons.hideColumns")}
</Button>
</Dropdown>
<Button type="primary" icon={<ShareAltOutlined />} onClick={() => {
let url = shareSavedState("filamentList-v2");
try {
if (navigator.canShare()) {
navigator.share({ url: url });
} else {
window.location.hash = url.split("#")[1]
}
} catch (err) {
console.error(err);
}
}}>
{t("buttons.share")}
</Button>
{defaultButtons}
</>
)}

View File

@@ -5,8 +5,8 @@ import { Table, Space, Button, Dropdown, Modal } from "antd";
import dayjs from "dayjs";
import utc from "dayjs/plugin/utc";
import { ISpool } from "./model";
import { TableState, useInitialTableState, useSavedState, useStoreInitialState } from "../../utils/saveload";
import { EditOutlined, FilterOutlined, InboxOutlined, ToTopOutlined } from "@ant-design/icons";
import { TableState, shareSavedState, useInitialTableState, useSavedState, useStoreInitialState } from "../../utils/saveload";
import { EditOutlined, FilterOutlined, InboxOutlined, ShareAltOutlined, ToTopOutlined } from "@ant-design/icons";
import {
DateColumn,
FilteredQueryColumn,
@@ -221,6 +221,20 @@ export const SpoolList: React.FC<IResourceComponentsProps> = () => {
{t("buttons.hideColumns")}
</Button>
</Dropdown>
<Button type="primary" icon={<ShareAltOutlined />} onClick={() => {
let url = shareSavedState("spoolList-v2");
try {
if (navigator.canShare()) {
navigator.share({ url: url });
} else {
window.location.hash = url.split("#")[1]
}
} catch (err) {
console.error(err);
}
}}>
{t("buttons.share")}
</Button>
{defaultButtons}
</>
)}

View File

@@ -5,8 +5,8 @@ import { Table, Space, Button, Dropdown } from "antd";
import dayjs from "dayjs";
import utc from "dayjs/plugin/utc";
import { IVendor } from "./model";
import { TableState, useInitialTableState, useStoreInitialState } from "../../utils/saveload";
import { EditOutlined, FilterOutlined } from "@ant-design/icons";
import { TableState, shareSavedState, useInitialTableState, useStoreInitialState } from "../../utils/saveload";
import { EditOutlined, FilterOutlined, ShareAltOutlined } from "@ant-design/icons";
import { DateColumn, RichColumn, SortedColumn } from "../../components/column";
import { useLiveify } from "../../components/liveify";
@@ -110,6 +110,20 @@ export const VendorList: React.FC<IResourceComponentsProps> = () => {
{t("buttons.hideColumns")}
</Button>
</Dropdown>
<Button type="primary" icon={<ShareAltOutlined />} onClick={() => {
let url = shareSavedState("vendorList-v2");
try {
if (navigator.canShare()) {
navigator.share({ url: url });
} else {
window.location.hash = url.split("#")[1]
}
} catch (err) {
console.error(err);
}
}}>
{t("buttons.share")}
</Button>
{defaultButtons}
</>
)}

View File

@@ -16,15 +16,16 @@ export interface TableState {
export function useInitialTableState(tableId: string): TableState {
const [initialState] = React.useState(() => {
const savedSorters = isLocalStorageAvailable ? localStorage.getItem(`${tableId}-sorters`) : null;
const savedFilters = isLocalStorageAvailable ? localStorage.getItem(`${tableId}-filters`) : null;
const savedPagination = isLocalStorageAvailable ? localStorage.getItem(`${tableId}-pagination`) : null;
const savedShowColumns = isLocalStorageAvailable ? localStorage.getItem(`${tableId}-showColumns`) : null;
const savedSorters = hasHashProperty(`${tableId}-sorters`) ? getHashProperty(`${tableId}-sorters`) : isLocalStorageAvailable ? localStorage.getItem(`${tableId}-sorters`) : null;
const savedFilters = hasHashProperty(`${tableId}-filters`) ? getHashProperty(`${tableId}-filters`) : isLocalStorageAvailable ? localStorage.getItem(`${tableId}-filters`) : null;
const savedPagination = hasHashProperty(`${tableId}-pagination`) ? getHashProperty(`${tableId}-pagination`) : isLocalStorageAvailable ? localStorage.getItem(`${tableId}-pagination`) : null;
const savedShowColumns = hasHashProperty(`${tableId}-showColumns`) ? getHashProperty(`${tableId}-showColumns`) : isLocalStorageAvailable ? localStorage.getItem(`${tableId}-showColumns`) : null;
const sorters = savedSorters ? JSON.parse(savedSorters) : [{ field: "id", order: "asc" }];
const filters = savedFilters ? JSON.parse(savedFilters) : [];
const pagination = savedPagination ? JSON.parse(savedPagination) : { page: 1, pageSize: 20 };
const showColumns = savedShowColumns ? JSON.parse(savedShowColumns) : undefined;
window.location.hash = "";
return { sorters, filters, pagination, showColumns };
});
return initialState;
@@ -74,3 +75,25 @@ export function useSavedState<T>(id: string, defaultValue: T) {
return [state, setState] as const;
}
export function shareSavedState(tableId: string): string {
const tableStates = ['sorters', 'filters', 'pagination', 'showColumns'];
const params = new URLSearchParams();
tableStates.forEach(s => {
let l = localStorage.getItem(`${tableId}-${s}`);
if (l) {
params.append(`${tableId}-${s}`, l);
}
})
return `${window.location.origin}${window.location.pathname}#${params.toString()}`
}
function getHashProperty(Id: string) {
const hash = new URLSearchParams(window.location.hash.substring(1));
return hash.get(Id);
}
function hasHashProperty(property: string): boolean {
const hash = new URLSearchParams(window.location.hash.substring(1));
return hash.has(property);
}