diff --git a/catalog-rest-service/src/main/resources/ui/src/components/Loader/Loader.css b/catalog-rest-service/src/main/resources/ui/src/components/Loader/Loader.css
index 906f8e71f20..e578acdcf22 100644
--- a/catalog-rest-service/src/main/resources/ui/src/components/Loader/Loader.css
+++ b/catalog-rest-service/src/main/resources/ui/src/components/Loader/Loader.css
@@ -20,12 +20,32 @@
height: 50px;
border-radius: 50%;
border: 5px solid rgba(0, 0, 0, 0.1);
- border-left-color: rgba(37, 99, 235, 1);
+ border-left-color: #7147e8;
background: transparent;
animation: rotate 1s linear infinite;
margin: 6rem auto;
}
+.loader.loader-sm {
+ width: 20px;
+ height: 20px;
+ border-width: 2px;
+ margin: auto;
+}
+
+.loader.loader-success {
+ border-left-color: #51c41a;
+}
+
+.loader.loader-error {
+ border-left-color: #ff4c3b;
+}
+
+.loader.loader-white {
+ border-color: #ffffff;
+ border-right-color: transparent;
+}
+
@keyframes rotate {
from {
transform: rotate(0);
diff --git a/catalog-rest-service/src/main/resources/ui/src/components/Loader/Loader.tsx b/catalog-rest-service/src/main/resources/ui/src/components/Loader/Loader.tsx
index 274b56f04f5..bf44b4c1e4c 100644
--- a/catalog-rest-service/src/main/resources/ui/src/components/Loader/Loader.tsx
+++ b/catalog-rest-service/src/main/resources/ui/src/components/Loader/Loader.tsx
@@ -15,10 +15,46 @@
* limitations under the License.
*/
-import React from 'react';
+import React, { FunctionComponent } from 'react';
import './Loader.css';
-const Loader: Function = (): JSX.Element => {
- return
;
+
+type Props = {
+ size?: 'default' | 'small';
+ type?: 'default' | 'success' | 'error' | 'white';
+};
+
+const Loader: FunctionComponent = ({
+ size = 'default',
+ type = 'default',
+}: Props): JSX.Element => {
+ let classes = 'loader';
+ switch (size) {
+ case 'small':
+ classes += ' loader-sm';
+
+ break;
+ default:
+ break;
+ }
+
+ switch (type) {
+ case 'success':
+ classes += ' loader-success';
+
+ break;
+ case 'error':
+ classes += ' loader-error';
+
+ break;
+ case 'white':
+ classes += ' loader-white';
+
+ break;
+ default:
+ break;
+ }
+
+ return ;
};
export default Loader;
diff --git a/catalog-rest-service/src/main/resources/ui/src/components/my-data-details/ManageTab.tsx b/catalog-rest-service/src/main/resources/ui/src/components/my-data-details/ManageTab.tsx
index b98f32b6ef9..963dd7df8f6 100644
--- a/catalog-rest-service/src/main/resources/ui/src/components/my-data-details/ManageTab.tsx
+++ b/catalog-rest-service/src/main/resources/ui/src/components/my-data-details/ManageTab.tsx
@@ -24,11 +24,15 @@ import SVGIcons from '../../utils/SvgUtils';
import { Button } from '../buttons/Button/Button';
import CardListItem from '../card-list/CardListItem/CardWithListItems';
import DropDownList from '../dropdown/DropDownList';
+import Loader from '../Loader/Loader';
type Props = {
currentTier?: string;
currentUser?: string;
- onSave: (owner: TableDetail['owner'], tier: TableDetail['tier']) => void;
+ onSave: (
+ owner: TableDetail['owner'],
+ tier: TableDetail['tier']
+ ) => Promise;
};
const ManageTab: FunctionComponent = ({
@@ -37,6 +41,10 @@ const ManageTab: FunctionComponent = ({
onSave,
}: Props) => {
const { data } = cardData;
+ const [loading, setLoading] = useState(false);
+ const [status, setStatus] = useState<'initial' | 'waiting' | 'success'>(
+ 'initial'
+ );
const [activeTier, setActiveTier] = useState(currentTier);
const [listVisible, setListVisible] = useState(false);
const [listOwners] = useState(() => {
@@ -81,6 +89,8 @@ const ManageTab: FunctionComponent = ({
};
const handleSave = () => {
+ setLoading(true);
+ setStatus('waiting');
// Save API call goes here...
const newOwner: TableDetail['owner'] =
owner !== currentUser
@@ -90,7 +100,10 @@ const ManageTab: FunctionComponent = ({
}
: undefined;
const newTier = activeTier !== currentTier ? activeTier : undefined;
- onSave(newOwner, newTier);
+ onSave(newOwner, newTier).catch(() => {
+ setStatus('initial');
+ setLoading(false);
+ });
};
const handleCancel = () => {
@@ -106,6 +119,18 @@ const ManageTab: FunctionComponent = ({
setOwner(currentUser);
}, [currentUser]);
+ useEffect(() => {
+ setTimeout(() => {
+ setLoading(false);
+ }, 1000);
+ if (status === 'waiting') {
+ setStatus('success');
+ setTimeout(() => {
+ setStatus('initial');
+ }, 3000);
+ }
+ }, [currentTier, currentUser]);
+
return (
@@ -154,13 +179,34 @@ const ManageTab: FunctionComponent
= ({
onClick={handleCancel}>
Discard
-
+ {loading ? (
+
+ ) : status === 'success' ? (
+
+ ) : (
+
+ )}
);
diff --git a/catalog-rest-service/src/main/resources/ui/src/pages/my-data-details/index.tsx b/catalog-rest-service/src/main/resources/ui/src/pages/my-data-details/index.tsx
index 127fb1e24df..66fdc7ce972 100644
--- a/catalog-rest-service/src/main/resources/ui/src/pages/my-data-details/index.tsx
+++ b/catalog-rest-service/src/main/resources/ui/src/pages/my-data-details/index.tsx
@@ -223,31 +223,38 @@ const MyDataDetailsPage = () => {
const onSettingsUpdate = (
newOwner?: TableDetail['owner'],
newTier?: TableDetail['tier']
- ) => {
- if (newOwner || newTier) {
- const tierTag: TableDetail['tags'] = newTier
- ? [
- ...getTagsWithoutTier(tableDetails.tags),
- { tagFQN: newTier, labelType: 'Manual', state: 'Confirmed' },
- ]
- : tableDetails.tags;
- const updatedTableDetails = {
- ...tableDetails,
- owner: newOwner
- ? {
- ...tableDetails.owner,
- ...newOwner,
- }
- : tableDetails.owner,
- // tier: newTier || tableDetails.tier,
- tags: tierTag,
- };
- saveUpdatedTableData(updatedTableDetails).then((res) => {
- setTableDetails(res.data);
- setOwner(res.data.owner);
- setTier(getTierFromTableTags(res.data.tags));
- });
- }
+ ): Promise => {
+ return new Promise((resolve, reject) => {
+ if (newOwner || newTier) {
+ const tierTag: TableDetail['tags'] = newTier
+ ? [
+ ...getTagsWithoutTier(tableDetails.tags),
+ { tagFQN: newTier, labelType: 'Manual', state: 'Confirmed' },
+ ]
+ : tableDetails.tags;
+ const updatedTableDetails = {
+ ...tableDetails,
+ owner: newOwner
+ ? {
+ ...tableDetails.owner,
+ ...newOwner,
+ }
+ : tableDetails.owner,
+ // tier: newTier || tableDetails.tier,
+ tags: tierTag,
+ };
+ saveUpdatedTableData(updatedTableDetails)
+ .then((res) => {
+ setTableDetails(res.data);
+ setOwner(res.data.owner);
+ setTier(getTierFromTableTags(res.data.tags));
+ resolve();
+ })
+ .catch(() => reject());
+ } else {
+ reject();
+ }
+ });
};
const onSuggest = (updatedHTML: string) => {
diff --git a/catalog-rest-service/src/main/resources/ui/tailwind.config.js b/catalog-rest-service/src/main/resources/ui/tailwind.config.js
index 5bb7adc1e90..991a8cd4d20 100644
--- a/catalog-rest-service/src/main/resources/ui/tailwind.config.js
+++ b/catalog-rest-service/src/main/resources/ui/tailwind.config.js
@@ -67,10 +67,6 @@ module.exports = {
search: '#D5D6D9',
},
colors: {
- success: success,
- error: error,
- warning: warning,
- info: info,
'grey-body': textBody,
'grey-muted': textMuted,
'grey-muted-lite': textMutedLite,
@@ -83,6 +79,10 @@ module.exports = {
'body-main': bodyBG,
'body-hover': bodyHoverBG,
tag: tagBG,
+ success: success,
+ error: error,
+ warning: warning,
+ info: info,
},
fontFamily: {
sans: ['Inter', ...defaultTheme.fontFamily.sans],
@@ -117,6 +117,7 @@ module.exports = {
borderStyle: ['hover'],
borderWidth: ['hover'],
display: ['group-hover'],
+ opacity: ['disabled'],
},
},
plugins: [require('@tailwindcss/custom-forms')],