Merge branch 'develop' into rc

This commit is contained in:
shamsmosowi
2021-11-20 15:03:01 +11:00
11 changed files with 222 additions and 42 deletions

View File

@@ -202,9 +202,7 @@ export default function BulkActions({ selectedRows, columns, clearSelection }) {
};
const executeAction = async (key: string, actionType: string) => {
const actionColumn = _find(actionColumns, { key });
console.log(actionColumn);
if (!actionColumn) return;
console.log(actionColumn);
if (actionColumn.config.isActionScript) {
handleActionScript(actionColumn, actionType);
} else {

View File

@@ -82,8 +82,6 @@ export const cloudLogFetcher = (
.join(encodeURIComponent("\n"))}`
: "");
console.log(logQueryUrl);
if (rowyRun)
return rowyRun<Record<string, any>[]>({
route: { path: logQueryUrl, method: "GET" },

View File

@@ -52,7 +52,7 @@ export default function ImportCsvWizard({
const [open, setOpen] = useState(true);
const { tableState, tableActions, addRow } = useProjectContext();
const { tableState, tableActions, addRows } = useProjectContext();
const { enqueueSnackbar } = useSnackbar();
const [config, setConfig] = useState<CsvConfig>({
@@ -87,10 +87,10 @@ export default function ImportCsvWizard({
}, [csvData, tableState, config]);
const handleFinish = () => {
if (!tableState || !tableActions || !addRow || !parsedRows) return;
if (!tableState || !tableActions || !addRows || !parsedRows) return;
enqueueSnackbar("Importing data…");
// Add all new rows — synchronous
parsedRows!.forEach((newRow) => addRow(newRow, true));
addRows(parsedRows.map((r) => ({ data: r })).reverse(), true);
// Add any new columns to the end
for (const col of config.newColumns) {

View File

@@ -96,7 +96,6 @@ export default function ActionFab({
} else {
result = await handleCallableAction(data);
}
console.log(result);
const { message, success } = result;
setIsRunning(false);
enqueueSnackbar(JSON.stringify(message), {

View File

@@ -141,7 +141,6 @@ export default function ConnectTableSelect({
params: [algoliaIndex as string],
});
const { key } = resp;
console.log(key);
if (key) {
const newKey = {
key,

View File

@@ -28,7 +28,6 @@ export const filterOperators: IFilterOperator[] = [
];
export const valueFormatter = (value: any) => {
console.log(value);
if (value && value.toDate) {
return value.toDate();
}

View File

@@ -73,7 +73,6 @@ export const AppProvider: React.FC = ({ children }) => {
const token: any = jwt_decode(authToken);
if (token && token.exp * 1000 < Date.now()) {
// token is expired
console.log("token is expired,getting new token");
const res = await currentUser.getIdTokenResult(true);
setAuthToken(res.token as string);
return res.token;
@@ -125,7 +124,6 @@ export const AppProvider: React.FC = ({ children }) => {
if (currentUser[curr]) return { ...acc, [curr]: currentUser[curr] };
return acc;
}, {});
console.log("create user", userDoc.path, user);
db.doc(userDoc.path).set({ user }, { merge: true });
}
}, [userDoc, currentUser]);

View File

@@ -47,7 +47,15 @@ export interface IProjectContext {
roles: string[];
tableState: TableState;
tableActions: TableActions;
addRow: (data?: Record<string, any>, ignoreRequiredFields?: boolean) => void;
addRow: (
data?: Record<string, any>,
ignoreRequiredFields?: boolean,
id?: string
) => void;
addRows: (
rows: { data?: Record<string, any>; id?: string }[],
ignoreRequiredFields?: boolean
) => void;
deleteRow: (rowId) => void;
updateCell: (
ref: firebase.firestore.DocumentReference,
@@ -225,6 +233,53 @@ export const ProjectContextProvider: React.FC = ({ children }) => {
return;
};
const addRows = async (
rows: { data?: any; id?: string }[],
ignoreRequiredFields?: boolean
) => {
const valuesFromFilter = tableState.filters.reduce((acc, curr) => {
if (curr.operator === "==") {
return { ...acc, [curr.key]: curr.value };
} else {
return acc;
}
}, {});
const initialData = Object.values(tableState.columns).reduce(
(acc, column) => {
if (column.config?.defaultValue?.type === "static") {
return { ...acc, [column.key]: column.config.defaultValue.value };
} else if (column.config?.defaultValue?.type === "null") {
return { ...acc, [column.key]: null };
} else {
return acc;
}
},
{}
);
const requiredFields = Object.values(tableState.columns)
.filter((column) => column.config.required)
.map((column) => column.key);
if (table?.audit !== false) {
initialData[table?.auditFieldCreatedBy || "_createdBy"] = rowyUser(
currentUser!
);
initialData[table?.auditFieldUpdatedBy || "_updatedBy"] = rowyUser(
currentUser!
);
}
await tableActions.addRows(
rows.map((row) => ({
data: { ...valuesFromFilter, ...initialData, ...row.data },
})),
ignoreRequiredFields ? [] : requiredFields,
(rowId: string) => auditChange("ADD_ROW", rowId, {})
);
return;
};
const updateCell: IProjectContext["updateCell"] = (
ref,
fieldName,
@@ -330,6 +385,7 @@ export const ProjectContextProvider: React.FC = ({ children }) => {
tableState,
tableActions,
addRow,
addRows,
updateCell,
deleteRow,
settingsActions,

View File

@@ -10,6 +10,7 @@ export type TableActions = {
update: Function;
reorder: Function;
};
addRows: Function;
row: { add: Function; delete: Function; more: Function; update: Function };
table: {
set: (id: string, collection: string, filters: TableFilter[]) => void;
@@ -94,6 +95,7 @@ export default function useTable() {
remove: configActions.remove,
reorder: configActions.reorder,
},
addRows: tableActions.addRows,
row: {
add: tableActions.addRow,
update: tableActions.updateRow,

View File

@@ -13,8 +13,8 @@ import { useAppContext } from "@src/contexts/AppContext";
import { TableFilter, TableOrder } from ".";
import {
isCollectionGroup,
generateSmallerId,
missingFieldsReducer,
decrementId,
} from "@src/utils/fns";
// Safety parameter sets the upper limit of number of docs fetched by this hook
@@ -99,7 +99,6 @@ const useTableData = () => {
tableInitialState
);
const [rows, rowsDispatch] = useReducer(rowsReducer, []);
/** set collection listener
* @param filters
* @param limit max number of docs
@@ -252,7 +251,6 @@ const useTableData = () => {
return rowsDispatch({ type: "delete", rowId });
}
} catch (error: any) {
console.log(error);
if (error.code === "permission-denied") {
enqueueSnackbar("You do not have the permissions to delete this row.", {
variant: "error",
@@ -282,21 +280,22 @@ const useTableData = () => {
const addRow = async (
data: any,
requiredFields: string[],
onSuccess: (rowId: string) => void
onSuccess: (rowId: string) => void,
id?: string
) => {
const missingRequiredFields = requiredFields
? requiredFields.reduce(missingFieldsReducer(data), [])
: [];
const { path } = tableState;
let rowIndex = 0;
let seedId = rows[rowIndex]?.id ?? "zzzzzzzzzzzzzzzzzzzz";
while (seedId.split("").every((char) => char === "0")) {
rowIndex += 1;
seedId = rows[rowIndex].id;
}
const newId = generateSmallerId(seedId);
const newId =
id ??
decrementId(
rows[0]?.id ?? "zzzzzzzzzzzzzzzzzzzzzzzz",
Math.round(Math.random() * 100)
);
//generateSmallerId(rows[0]?.id ?? "zzzzzzzzzzzzzzzzzzzzzzzz");
if (missingRequiredFields.length === 0) {
try {
await db
@@ -327,6 +326,57 @@ const useTableData = () => {
}
};
/** creating new rows from array
* @param rows
* @param onSuccess
* @param requiredFields
*/
const addRows = async (
rows: { data: any; id?: string }[],
requiredFields: string[],
onSuccess: (rowIds: string) => void
) => {
let previousId = rows[0]?.id ?? "zzzzzzzzzzzzzzzzzzzzzzzz";
rows.forEach(async (row) => {
const { data, id } = row;
const missingRequiredFields = requiredFields
? requiredFields.reduce(missingFieldsReducer(data), [])
: [];
const newId =
id ?? decrementId(previousId, Math.round(Math.random() * 100));
previousId = newId;
if (missingRequiredFields.length === 0) {
try {
await db
.collection(tableState.path)
.doc(newId)
.set(data, { merge: true })
.then(() => {
onSuccess(newId);
});
} catch (error: any) {
if (error.code === "permission-denied") {
enqueueSnackbar(
"You do not have the permissions to add new rows.",
{
variant: "error",
}
);
}
}
} else {
const ref = db.collection(tableState.path).doc(newId);
const newRow = {
...data,
id: newId,
ref,
_missingRequiredFields: missingRequiredFields,
};
rowsDispatch({ type: "add", newRow });
}
});
};
const updateRow = (rowRef, update, onSuccess, onError) => {
rowsDispatch({ type: "update", update, rowRef, onSuccess, onError });
};
@@ -350,6 +400,7 @@ const useTableData = () => {
deleteRow,
setTable,
addRow,
addRows,
updateRow,
moreRows,
dispatch: tableDispatch,

View File

@@ -84,6 +84,104 @@ export const makeId = (length: number = 20) => {
return result;
};
function convertBase(str, fromBase, toBase) {
const add = (x, y, base: number) => {
let z: number[] = [];
const n = Math.max(x.length, y.length);
let carry = 0;
let i = 0;
while (i < n || carry) {
const xi = i < x.length ? x[i] : 0;
const yi = i < y.length ? y[i] : 0;
const zi = carry + xi + yi;
z.push(zi % base);
carry = Math.floor(zi / base);
i++;
}
return z;
};
const multiplyByNumber = (num, x, base) => {
if (num < 0) return null;
if (num == 0) return [];
let result: number[] = [];
let power = x;
while (true) {
num & 1 && (result = add(result, power, base));
num = num >> 1;
if (num === 0) break;
power = add(power, power, base);
}
return result;
};
const parseToDigitsArray = (str, base) => {
const digits = str.split("");
let arr: number[] = [];
for (let i = digits.length - 1; i >= 0; i--) {
const n = characters.indexOf(digits[i]);
if (n == -1) return "0";
arr.push(n);
}
return arr;
};
const digits = parseToDigitsArray(str, fromBase);
if (digits === null) return "0";
let outArray: number[] = [];
let power: number[] | null = [1];
for (let i = 0; i < digits.length; i++) {
digits[i] &&
(outArray = add(
outArray,
multiplyByNumber(digits[i], power, toBase),
toBase
));
power = multiplyByNumber(fromBase, power, toBase);
}
let out = "";
for (let i = outArray.length - 1; i >= 0; i--) out += characters[outArray[i]];
return out;
}
export const decrementId = (id, dec = 1) => {
let newId = id.split("");
const trailingZeros: string[] = [];
const leadingZeros: string[] = [];
const leadingId: string[] = [];
while (newId[0] == "0") {
leadingZeros.push(newId.shift());
}
// remove all the zeros
while (newId[newId.length - 1] == "0") {
trailingZeros.push(newId.pop());
}
// put back at most 6 zeros
newId = newId.concat(trailingZeros.splice(0, 6));
while (newId.length > 8) {
leadingId.push(newId.shift());
}
const currentIndex: string | null = convertBase(newId.join(""), 62, 10);
if (currentIndex === null) throw new Error("Could not convert id to number");
if (parseInt(currentIndex) < 1 || Number.isNaN(parseInt(currentIndex)))
return `${id}${convertBase(`${Math.random() * 10000}`, 10, 62)}`;
console.log({ id, val: parseInt(currentIndex) });
const newIndex = parseInt(currentIndex) - dec;
return `${leadingZeros.join("")}${leadingId.join("")}${convertBase(
`${newIndex}`,
10,
62
)}${trailingZeros.join("")}`;
};
export const generateSmallerId = (id: string) => {
const generated = id.split("");
for (let i = generated.length - 1; i >= 0; i--) {
@@ -106,24 +204,6 @@ export const generateSmallerId = (id: string) => {
return generated.join("");
};
export const generateBiggerId = (id: string) => {
const generated = id.split("");
for (let i = generated.length - 1; i >= 0; i--) {
const charIndex = characters.indexOf(id[i]);
console.log(i, id[i], charIndex);
if (charIndex < characters.length - 1) {
generated[i] = characters[charIndex + 1];
break;
} else if (i > 0) {
continue;
} else {
generated.push(characters[0]);
}
}
return generated.join("");
};
// Gets sub-table ID in $1
const formatPathRegex = /\/[^\/]+\/([^\/]+)/g;