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é", "showArchived": "Zobrazit archivované",
"notAccessTitle": "Nemáte oprávnění k přístupu", "notAccessTitle": "Nemáte oprávnění k přístupu",
"hideColumns": "Skrýt sloupce", "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.", "warnWhenUnsavedChanges": "Jste si jisti, že chcete odejít? Máte neuložené změny.",
"notifications": { "notifications": {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -27,7 +27,8 @@
"showArchived": "Visa arkiverade", "showArchived": "Visa arkiverade",
"notAccessTitle": "Du har inte tillgång till denna sida", "notAccessTitle": "Du har inte tillgång till denna sida",
"hideColumns": "Dölj kolumner", "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.", "warnWhenUnsavedChanges": "Är du säker på att du vill lämna sidan? Du har osparade ändringar.",
"notifications": { "notifications": {

View File

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

View File

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

View File

@@ -5,8 +5,8 @@ import { Table, Space, Button, Dropdown } from "antd";
import dayjs from "dayjs"; import dayjs from "dayjs";
import utc from "dayjs/plugin/utc"; import utc from "dayjs/plugin/utc";
import { IFilament } from "./model"; import { IFilament } from "./model";
import { EditOutlined, FilterOutlined } from "@ant-design/icons"; import { EditOutlined, FilterOutlined, ShareAltOutlined } from "@ant-design/icons";
import { TableState, useInitialTableState, useStoreInitialState } from "../../utils/saveload"; import { TableState, shareSavedState, useInitialTableState, useStoreInitialState } from "../../utils/saveload";
import { import {
DateColumn, DateColumn,
FilteredQueryColumn, FilteredQueryColumn,
@@ -164,6 +164,20 @@ export const FilamentList: React.FC<IResourceComponentsProps> = () => {
{t("buttons.hideColumns")} {t("buttons.hideColumns")}
</Button> </Button>
</Dropdown> </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} {defaultButtons}
</> </>
)} )}

View File

@@ -5,8 +5,8 @@ import { Table, Space, Button, Dropdown, Modal } from "antd";
import dayjs from "dayjs"; import dayjs from "dayjs";
import utc from "dayjs/plugin/utc"; import utc from "dayjs/plugin/utc";
import { ISpool } from "./model"; import { ISpool } from "./model";
import { TableState, useInitialTableState, useSavedState, useStoreInitialState } from "../../utils/saveload"; import { TableState, shareSavedState, useInitialTableState, useSavedState, useStoreInitialState } from "../../utils/saveload";
import { EditOutlined, FilterOutlined, InboxOutlined, ToTopOutlined } from "@ant-design/icons"; import { EditOutlined, FilterOutlined, InboxOutlined, ShareAltOutlined, ToTopOutlined } from "@ant-design/icons";
import { import {
DateColumn, DateColumn,
FilteredQueryColumn, FilteredQueryColumn,
@@ -221,6 +221,20 @@ export const SpoolList: React.FC<IResourceComponentsProps> = () => {
{t("buttons.hideColumns")} {t("buttons.hideColumns")}
</Button> </Button>
</Dropdown> </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} {defaultButtons}
</> </>
)} )}

View File

@@ -5,8 +5,8 @@ import { Table, Space, Button, Dropdown } from "antd";
import dayjs from "dayjs"; import dayjs from "dayjs";
import utc from "dayjs/plugin/utc"; import utc from "dayjs/plugin/utc";
import { IVendor } from "./model"; import { IVendor } from "./model";
import { TableState, useInitialTableState, useStoreInitialState } from "../../utils/saveload"; import { TableState, shareSavedState, useInitialTableState, useStoreInitialState } from "../../utils/saveload";
import { EditOutlined, FilterOutlined } from "@ant-design/icons"; import { EditOutlined, FilterOutlined, ShareAltOutlined } from "@ant-design/icons";
import { DateColumn, RichColumn, SortedColumn } from "../../components/column"; import { DateColumn, RichColumn, SortedColumn } from "../../components/column";
import { useLiveify } from "../../components/liveify"; import { useLiveify } from "../../components/liveify";
@@ -110,6 +110,20 @@ export const VendorList: React.FC<IResourceComponentsProps> = () => {
{t("buttons.hideColumns")} {t("buttons.hideColumns")}
</Button> </Button>
</Dropdown> </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} {defaultButtons}
</> </>
)} )}

View File

@@ -16,15 +16,16 @@ export interface TableState {
export function useInitialTableState(tableId: string): TableState { export function useInitialTableState(tableId: string): TableState {
const [initialState] = React.useState(() => { const [initialState] = React.useState(() => {
const savedSorters = isLocalStorageAvailable ? localStorage.getItem(`${tableId}-sorters`) : null; const savedSorters = hasHashProperty(`${tableId}-sorters`) ? getHashProperty(`${tableId}-sorters`) : isLocalStorageAvailable ? localStorage.getItem(`${tableId}-sorters`) : null;
const savedFilters = isLocalStorageAvailable ? localStorage.getItem(`${tableId}-filters`) : null; const savedFilters = hasHashProperty(`${tableId}-filters`) ? getHashProperty(`${tableId}-filters`) : isLocalStorageAvailable ? localStorage.getItem(`${tableId}-filters`) : null;
const savedPagination = isLocalStorageAvailable ? localStorage.getItem(`${tableId}-pagination`) : null; const savedPagination = hasHashProperty(`${tableId}-pagination`) ? getHashProperty(`${tableId}-pagination`) : isLocalStorageAvailable ? localStorage.getItem(`${tableId}-pagination`) : null;
const savedShowColumns = isLocalStorageAvailable ? localStorage.getItem(`${tableId}-showColumns`) : 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 sorters = savedSorters ? JSON.parse(savedSorters) : [{ field: "id", order: "asc" }];
const filters = savedFilters ? JSON.parse(savedFilters) : []; const filters = savedFilters ? JSON.parse(savedFilters) : [];
const pagination = savedPagination ? JSON.parse(savedPagination) : { page: 1, pageSize: 20 }; const pagination = savedPagination ? JSON.parse(savedPagination) : { page: 1, pageSize: 20 };
const showColumns = savedShowColumns ? JSON.parse(savedShowColumns) : undefined; const showColumns = savedShowColumns ? JSON.parse(savedShowColumns) : undefined;
window.location.hash = "";
return { sorters, filters, pagination, showColumns }; return { sorters, filters, pagination, showColumns };
}); });
return initialState; return initialState;
@@ -74,3 +75,25 @@ export function useSavedState<T>(id: string, defaultValue: T) {
return [state, setState] as const; 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);
}