Skip to content

Commit

Permalink
Merge pull request #1 from bps-kota-bontang/staging
Browse files Browse the repository at this point in the history
Initial Release: Implement CI Configuration, Style Improvements, and Various Fixes
  • Loading branch information
newarifrh authored Aug 25, 2024
2 parents 98f2489 + 5713e21 commit 7bbcaf6
Show file tree
Hide file tree
Showing 28 changed files with 573 additions and 292 deletions.
1 change: 0 additions & 1 deletion .env.development

This file was deleted.

35 changes: 35 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Release Serambi Kami

on:
push:
branches: ["main"]

permissions:
contents: write
pull-requests: write

jobs:
release-please:
name: Release Serambi Kami
runs-on: ubuntu-latest
steps:
- uses: googleapis/release-please-action@v4
id: release
with:
token: ${{ secrets.GH_TOKEN }}
release-type: node
- uses: actions/checkout@v4
- name: tag major and minor versions
if: ${{ steps.release.outputs.release_created }}
run: |
git config user.name github-actions[bot]
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
git remote add gh-token "https://${{ secrets.GH_TOKEN }}@github.com/googleapis/release-please-action.git"
git tag -d v${{ steps.release.outputs.major }} || true
git tag -d v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }} || true
git push origin :v${{ steps.release.outputs.major }} || true
git push origin :v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }} || true
git tag -a v${{ steps.release.outputs.major }} -m "Release v${{ steps.release.outputs.major }}"
git tag -a v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }} -m "Release v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }}"
git push origin v${{ steps.release.outputs.major }}
git push origin v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }}
2 changes: 1 addition & 1 deletion Dockerfile.production
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM oven/bun:1.1.12-alpine AS build-stage
FROM oven/bun:1.1.25-alpine AS build-stage
WORKDIR /app
COPY package.json bun.lockb ./
RUN bun install
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile.staging
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM oven/bun:1.1.12-alpine AS build-stage
FROM oven/bun:1.1.25-alpine AS build-stage
WORKDIR /app
COPY package.json bun.lockb ./
RUN bun install
Expand Down
25 changes: 14 additions & 11 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/serambi.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>%VITE_APP_NAME%</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/serambi.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>%VITE_APP_NAME%</title>
</head>

<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>

</html>
15 changes: 14 additions & 1 deletion src/api/Team.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,17 @@ export const createTeam = async (data: any) => {
}

return result.data;
};
};


export const deleteTeam = async (id: string) => {
const response = await fetch(`${API_BASE_URL}/v1/teams/${id}`, {
method: "DELETE",
credentials: "include",
});

if (!response.ok) {
const result = await response.json();
throw new Error(result.message);
}
};
68 changes: 68 additions & 0 deletions src/components/service/FormCredentialService.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { Credential } from "@/types/Credential";
import {
CheckCircleTwoTone,
CloseCircleTwoTone,
CopyOutlined,
} from "@ant-design/icons";
import { App, Button, Input, Space } from "antd";

interface FormCredentialServiceProps {
credential: Credential;
}

const FormCredentialService = ({ credential }: FormCredentialServiceProps) => {
const { message } = App.useApp();

const handleCopy = (text?: string) => {
if (!text) return;
navigator.clipboard.writeText(text).then(() => {
message.success({
content: "Kredensial berhasil disalin",
});
});
};
return (
<div className="flex flex-col gap-3">
{credential.username && (
<>
<span className="text-sm">Nama Pengguna</span>
<Space.Compact>
<Input.Password value={credential.username} />
<Button
onClick={() => handleCopy(credential.username)}
icon={<CopyOutlined />}
/>
</Space.Compact>
</>
)}
{credential.password && (
<>
<span className="text-sm">Kata Sandi</span>
<Space.Compact>
<Input.Password value={credential.password} />
<Button
onClick={() => handleCopy(credential.password)}
icon={<CopyOutlined />}
/>
</Space.Compact>
</>
)}
<span className="italic">
{credential.hasSso ? (
<>
<CheckCircleTwoTone twoToneColor={"#52c41a"} className="mr-1" />
Tersedia Single Sign On
</>
) : (
<>
<CloseCircleTwoTone twoToneColor={"#ff4d4f"} className="mr-1" />
Tidak Tersedia Single Sign On
</>
)}
</span>
<span className="italic">Catatan: {credential.note ?? "-"}</span>
</div>
);
};

export default FormCredentialService;
117 changes: 35 additions & 82 deletions src/components/service/ServiceItem.tsx
Original file line number Diff line number Diff line change
@@ -1,59 +1,19 @@
import { deleteService, getService } from "@/api/Service";
import { Service } from "@/types/Service";
import {
CheckCircleTwoTone,
CloseCircleTwoTone,
CopyOutlined,
MoreOutlined,
} from "@ant-design/icons";
import { Button, Image, Input, message, App, Space, Dropdown } from "antd";
import { MoreOutlined } from "@ant-design/icons";
import { Button, Image, App, Dropdown } from "antd";
import { useNavigate } from "react-router-dom";
import FormCredentialService from "@/components/service/FormCredentialService";
import { useMediaQuery } from "@/hooks/useMediaQuery";

interface ServiceItemProps {
service: Service;
onItemDeleted: () => void;
}

const handleClick = (link: string) => {
window.open(link, "_blank");
};

const handleCopy = (text?: string) => {
if (!text) return;
navigator.clipboard.writeText(text).then(() => {
message.success({
content: "Kredensial berhasil disalin",
});
});
};

const CredentialField = ({
label,
value,
}: {
label: string;
value?: string;
}) => (
<Space.Compact>
<Input
value={value}
type={label === "password" ? "password" : "text"}
disabled
/>
<Button
onClick={(event) => {
event.stopPropagation();
handleCopy(value);
}}
icon={<CopyOutlined />}
aria-label={`Copy service ${label}`}
/>
</Space.Compact>
);

const ServiceItem = ({ service, onItemDeleted }: ServiceItemProps) => {
const { modal, notification } = App.useApp();

const isMobile = useMediaQuery();
const navigate = useNavigate();

const handleDeleteService = async (id: string) => {
Expand All @@ -73,6 +33,10 @@ const ServiceItem = ({ service, onItemDeleted }: ServiceItemProps) => {
}
};

const handleClick = (link: string) => {
window.open(link, "_blank");
};

const showModal = async () => {
try {
const serviceDetail = await getService(service.id);
Expand All @@ -86,36 +50,7 @@ const ServiceItem = ({ service, onItemDeleted }: ServiceItemProps) => {
closable: true,
okCancel: true,
title: `Kredensial Layanan: ${service.name}`,
content: (
<div className="flex flex-col gap-3">
{credential.username && (
<CredentialField label="username" value={credential.username} />
)}
{credential.password && (
<CredentialField label="password" value={credential.password} />
)}
<span className="italic">
{credential.hasSso ? (
<>
<CheckCircleTwoTone
twoToneColor={"#52c41a"}
className="mr-1"
/>
Tersedia Single Sign On
</>
) : (
<>
<CloseCircleTwoTone
twoToneColor={"#ff4d4f"}
className="mr-1"
/>
Tidak Tersedia Single Sign On
</>
)}
</span>
<span className="italic">Catatan: {credential.note ?? "-"}</span>
</div>
),
content: <FormCredentialService credential={credential} />,
cancelText: "Tutup",
okText: "Lihat",
onOk: () => handleClick(service.link),
Expand All @@ -130,7 +65,7 @@ const ServiceItem = ({ service, onItemDeleted }: ServiceItemProps) => {
};

return (
<div className="bg-white rounded-md drop-shadow-md p-5 gap-2 flex flex-col ">
<div className="relative bg-white rounded-md drop-shadow-md p-5 gap-2 flex flex-col ">
<Dropdown
menu={{
items: [
Expand All @@ -143,7 +78,18 @@ const ServiceItem = ({ service, onItemDeleted }: ServiceItemProps) => {
key: "delete",
label: "Hapus",
danger: true,
onClick: () => handleDeleteService(service.id),
onClick: () => {
modal.error({
maskClosable: true,
closable: true,
okCancel: true,
title: `Hapus Layanan: ${service.name}`,
content: "Apakah Anda yakin ingin menghapus layanan ini?",
cancelText: "Batal",
okText: "Hapus",
onOk: () => handleDeleteService(service.id),
});
},
},
],
}}
Expand All @@ -156,19 +102,26 @@ const ServiceItem = ({ service, onItemDeleted }: ServiceItemProps) => {
/>
</Dropdown>
<div>
<Image preview={false} height={48} src={service.imageUrl} />
<Image
preview={false}
height={isMobile ? undefined : 48}
width={isMobile ? 48 : undefined}
src={service.imageUrl}
/>
</div>
<div className="flex flex-col justify-center ">
<div className="flex flex-col justify-center flex-1">
<div className="text-lg text-black font-semibold">{service.name}</div>
<div className="text-sm text-gray-500 line-clamp-2">
<div className="text-sm text-gray-500 line-clamp-2 mb-5">
{service.description}
</div>
<div className="mt-5 flex flex-col gap-2">
<div className=" flex flex-col gap-2 mt-auto">
<Button type="primary" onClick={() => handleClick(service.link)}>
Lihat
</Button>
{service.credential && (
<Button onClick={showModal}>Tampilkan Kredensial</Button>
<Button onClick={showModal}>
{isMobile ? "Kredensial" : "Tampilkan Kredensial"}
</Button>
)}
</div>
</div>
Expand Down
13 changes: 13 additions & 0 deletions src/components/service/ServiceSkeletonItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Skeleton } from "antd";

const ServiceSkeletonItem = () => {
return (
<div className="bg-white rounded-md drop-shadow-md p-5 gap-2 flex flex-col ">
<Skeleton.Avatar />
<Skeleton paragraph />
<Skeleton.Button className="mt-2" />
</div>
);
};

export default ServiceSkeletonItem;
Loading

0 comments on commit 7bbcaf6

Please sign in to comment.