Full Express backend implementation

This commit is contained in:
Luke Hagar
2023-11-17 22:05:45 -06:00
parent 7289fde676
commit c34352339f
276 changed files with 289824 additions and 9975 deletions

2
.gitignore vendored
View File

@@ -14,3 +14,5 @@ yarn-error.log
pnpm-lock.yaml
.DS_Store
out/

1
.npmrc
View File

@@ -1 +0,0 @@
engine-strict = true

View File

@@ -1,12 +0,0 @@
{
"svelteSortOrder": "scripts-markup-styles",
"htmlWhitespaceSensitivity": "ignore",
"trailingComma": "all",
"requirePragma": false,
"bracketSpacing": true,
"singleQuote": true,
"printWidth": 100,
"useTabs": true,
"tabWidth": 4,
"semi": true
}

View File

@@ -1,3 +0,0 @@
{
"recommendations": ["svelte.svelte-vscode"]
}

View File

@@ -1,6 +0,0 @@
{
"[svelte]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "svelte.svelte-vscode"
}
}

92
Electron-App/.gitignore vendored Normal file
View File

@@ -0,0 +1,92 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
.DS_Store
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# Webpack
.webpack/
# Vite
.vite/
# Electron-Forge
out/

View File

@@ -0,0 +1,31 @@
module.exports = {
packagerConfig: {
asar: true,
extraResource: ["../Sveltekit-Build"],
},
rebuildConfig: {},
makers: [
{
name: "@electron-forge/maker-squirrel",
config: {},
},
{
name: "@electron-forge/maker-zip",
platforms: ["darwin"],
},
{
name: "@electron-forge/maker-deb",
config: {},
},
{
name: "@electron-forge/maker-rpm",
config: {},
},
],
plugins: [
{
name: "@electron-forge/plugin-auto-unpack-natives",
config: {},
},
],
};

5879
Electron-App/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

35
Electron-App/package.json Normal file
View File

@@ -0,0 +1,35 @@
{
"name": "idn-admin-console",
"productName": "IdentityNow Admin Console",
"version": "1.0.0",
"description": "A troubleshooting and administration app for IdentityNow",
"main": "src/index.js",
"scripts": {
"start": "electron-forge start",
"package": "electron-forge package",
"make": "electron-forge make",
"publish": "electron-forge publish",
"lint": "echo \"No linting configured\""
},
"keywords": [],
"author": {
"name": "Luke Hagar",
"email": "luke.hagar@sailpoint.com"
},
"license": "MIT",
"dependencies": {
"@electron-toolkit/utils": "^2.0.1",
"electron-log": "^5.0.0",
"electron-squirrel-startup": "^1.0.0",
"express": "^4.18.2"
},
"devDependencies": {
"@electron-forge/cli": "^7.0.0",
"@electron-forge/maker-deb": "^7.0.0",
"@electron-forge/maker-rpm": "^7.0.0",
"@electron-forge/maker-squirrel": "^7.0.0",
"@electron-forge/maker-zip": "^7.0.0",
"@electron-forge/plugin-auto-unpack-natives": "^7.0.0",
"electron": "27.1.0"
}
}

101
Electron-App/src/index.js Normal file
View File

@@ -0,0 +1,101 @@
const { app, BrowserWindow } = require("electron");
const path = require("path");
const { is } = require("@electron-toolkit/utils");
const handlerPkg = import(
is.dev
? "../../Sveltekit-Build/src/handler.js"
: `file://${path.join(
process.resourcesPath,
"Sveltekit-Build",
"src",
"handler.js"
)}`
);
const express = require("express");
const log = require("electron-log/main");
log.info(
"==================================Log Start=================================="
);
const port = 3000;
const origin = `http://localhost:${port}`;
log.info(`Starting server on ${origin}...`);
const server = express();
const createServer = async () => {
try {
log.info("Starting server...");
const { handler } = await handlerPkg;
// add a route that lives separately from the SvelteKit app
server.get("/healthcheck", (req, res) => {
log.info("Healthcheck route hit");
res.end("ok");
});
// let SvelteKit handle everything else, including serving prerendered pages and static assets
server.use(handler);
server.listen(3000, () => {
console.log(`Server listening on ${origin}`);
});
} catch (e) {
log.info(e);
}
};
createServer();
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
if (require("electron-squirrel-startup")) {
app.quit();
}
const createWindow = () => {
log.info("Creating window...");
// Create the browser window.
try {
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, "preload.js"),
},
});
log.info("Opening server in window...");
// and load the index.html of the app.
mainWindow.loadURL(origin);
// Open the DevTools.
mainWindow.webContents.openDevTools();
} catch (e) {
log.info("Error creating window");
log.info(e);
}
};
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on("ready", createWindow);
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on("window-all-closed", () => {
if (process.platform !== "darwin") {
app.quit();
}
});
app.on("activate", () => {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and import them here.

View File

@@ -0,0 +1,2 @@
// See the Electron documentation for details on how to use preload scripts:
// https://www.electronjs.org/docs/latest/tutorial/process-model#preload-scripts

View File

@@ -0,0 +1,13 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock

View File

@@ -0,0 +1,30 @@
module.exports = {
root: true,
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:svelte/recommended',
'prettier'
],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
parserOptions: {
sourceType: 'module',
ecmaVersion: 2020,
extraFileExtensions: ['.svelte']
},
env: {
browser: true,
es2017: true,
node: true
},
overrides: [
{
files: ['*.svelte'],
parser: 'svelte-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser'
}
}
]
};

10
Sveltekit-App/.gitignore vendored Normal file
View File

@@ -0,0 +1,10 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
vite.config.js.timestamp-*
vite.config.ts.timestamp-*

1
Sveltekit-App/.npmrc Normal file
View File

@@ -0,0 +1 @@
engine-strict=true

View File

@@ -0,0 +1,13 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock

View File

@@ -0,0 +1,8 @@
{
"useTabs": true,
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100,
"plugins": ["prettier-plugin-svelte"],
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
}

118
Sveltekit-App/.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,118 @@
{
"prettier.documentSelectors": [
"**/*.svelte"
],
"tailwindCSS.classAttributes": [
"class",
"accent",
"active",
"aspectRatio",
"background",
"badge",
"bgBackdrop",
"bgDark",
"bgDrawer",
"bgLight",
"blur",
"border",
"button",
"buttonAction",
"buttonBack",
"buttonClasses",
"buttonComplete",
"buttonDismiss",
"buttonNeutral",
"buttonNext",
"buttonPositive",
"buttonTextCancel",
"buttonTextConfirm",
"buttonTextFirst",
"buttonTextLast",
"buttonTextNext",
"buttonTextPrevious",
"buttonTextSubmit",
"caretClosed",
"caretOpen",
"chips",
"color",
"controlSeparator",
"controlVariant",
"cursor",
"display",
"element",
"fill",
"fillDark",
"fillLight",
"flex",
"gap",
"gridColumns",
"height",
"hover",
"inactive",
"indent",
"justify",
"meter",
"padding",
"position",
"regionAnchor",
"regionBackdrop",
"regionBody",
"regionCaption",
"regionCaret",
"regionCell",
"regionChildren",
"regionChipList",
"regionChipWrapper",
"regionCone",
"regionContent",
"regionControl",
"regionDefault",
"regionDrawer",
"regionFoot",
"regionFootCell",
"regionFooter",
"regionHead",
"regionHeadCell",
"regionHeader",
"regionIcon",
"regionInput",
"regionInterface",
"regionInterfaceText",
"regionLabel",
"regionLead",
"regionLegend",
"regionList",
"regionListItem",
"regionNavigation",
"regionPage",
"regionPanel",
"regionRowHeadline",
"regionRowMain",
"regionSummary",
"regionSymbol",
"regionTab",
"regionTrail",
"ring",
"rounded",
"select",
"shadow",
"slotDefault",
"slotFooter",
"slotHeader",
"slotLead",
"slotMessage",
"slotMeta",
"slotPageContent",
"slotPageFooter",
"slotPageHeader",
"slotSidebarLeft",
"slotSidebarRight",
"slotTrail",
"spacing",
"text",
"track",
"transition",
"width",
"zIndex"
]
}

38
Sveltekit-App/README.md Normal file
View File

@@ -0,0 +1,38 @@
# create-svelte
Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte).
## Creating a project
If you're seeing this, you've probably already done this step. Congrats!
```bash
# create a new project in the current directory
npm create svelte@latest
# create a new project in my-app
npm create svelte@latest my-app
```
## Developing
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
```bash
npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --open
```
## Building
To create a production version of your app:
```bash
npm run build
```
You can preview the production build with `npm run preview`.
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.

5107
Sveltekit-App/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,57 @@
{
"name": "idn-admin-console",
"description": "A troubleshooting and administration app for IdentityNow",
"version": "0.0.1",
"private": true,
"author": {
"name": "Luke Hagar",
"email": "luke.hagar@sailpoint.com"
},
"scripts": {
"dev": "vite dev",
"build": "cross-env ORIGIN=http://localhost:3000 vite build",
"preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"test": "vitest",
"lint": "prettier --check . && eslint .",
"format": "prettier --write ."
},
"devDependencies": {
"@skeletonlabs/skeleton": "2.5.0",
"@skeletonlabs/tw-plugin": "0.2.4",
"@sveltejs/adapter-auto": "^2.0.0",
"@sveltejs/adapter-node": "^1.3.1",
"@sveltejs/kit": "^1.27.4",
"@tailwindcss/forms": "0.5.7",
"@tailwindcss/typography": "0.5.10",
"@types/jsonwebtoken": "^9.0.5",
"@types/node": "20.9.1",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"alasql": "^4.2.2",
"autoprefixer": "10.4.16",
"axios": "^1.6.2",
"cross-env": "^7.0.3",
"eslint": "^8.28.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-svelte": "^2.30.0",
"jsonwebtoken": "^9.0.2",
"postcss": "8.4.31",
"prettier": "^3.0.0",
"prettier-plugin-svelte": "^3.0.0",
"sailpoint-api-client": "^1.3.0",
"svelte": "^4.0.5",
"svelte-check": "^3.6.0",
"tailwindcss": "3.3.5",
"tslib": "^2.4.1",
"typescript": "^5.0.0",
"vite": "^4.4.2",
"vite-plugin-tailwind-purgecss": "0.1.3",
"vitest": "^0.34.6"
},
"type": "module",
"dependencies": {
"@floating-ui/dom": "1.5.3"
}
}

View File

@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

15
Sveltekit-App/src/app.d.ts vendored Normal file
View File

@@ -0,0 +1,15 @@
// See https://kit.svelte.dev/docs/types#app
// for information about these interfaces
// and what to do when importing types
import type { AxiosError } from 'axios';
declare namespace App {
// interface Locals {}
// interface PageData {}
interface Error {
message: string;
AxiosError?: AxiosError;
Error?: Any;
}
// interface Platform {}
}

View File

@@ -1,7 +1,8 @@
/* Write your global styles here, in PostCSS syntax */
@tailwind base;
@tailwind components;
@tailwind utilities;
@tailwind variants;
:root [data-theme='wintry'] {
--theme-rounded-base: 5px;
--theme-rounded-container: 4px;

View File

@@ -1,7 +1,7 @@
import type { Cookies } from '@sveltejs/kit';
import axios from 'axios';
import jwt from 'jsonwebtoken'
import { error, redirect } from '@sveltejs/kit';
import jwt from 'jsonwebtoken';
import { redirect } from '@sveltejs/kit';
export function generateAuthLink(tenantUrl: string) {
return `${tenantUrl}/oauth/authorize?client_id=sailpoint-cli&response_type=code&redirect_uri=http://localhost:3000/callback`;
@@ -25,67 +25,61 @@ export type IdnSession = {
};
export async function refreshToken(apiUrl: string, refreshToken: string): Promise<IdnSession> {
let url = `${apiUrl}/oauth/token?grant_type=refresh_token&client_id=sailpoint-cli&refresh_token=${refreshToken}`
const response = await axios
.post(
url
)
.catch(function (err) {
const url = `${apiUrl}/oauth/token?grant_type=refresh_token&client_id=sailpoint-cli&refresh_token=${refreshToken}`;
const response = await axios.post(url).catch(function (err) {
if (err.response) {
// Request made and server responded
console.log(err.response.data);
console.log(err.response.status);
console.log(err.response.headers);
}
return undefined
return undefined;
});
// if (response) {
// console.log(response.data)
// }
const idnSession: IdnSession = response!.data as IdnSession;
return idnSession
return idnSession;
}
export async function getToken(cookies: Cookies): Promise<IdnSession> {
const idnSession = <IdnSession>JSON.parse(cookies.get('idnSession')!)
const session = JSON.parse(cookies.get('session')!)
const idnSession = <IdnSession>JSON.parse(cookies.get('idnSession')!);
const session = JSON.parse(cookies.get('session')!);
if (!idnSession && session) {
throw redirect(302, generateAuthLink(session.tenantUrl))
throw redirect(302, generateAuthLink(session.tenantUrl));
}
if (!idnSession && !session) {
throw redirect(302, "/")
throw redirect(302, '/');
}
if (isJwtExpired(idnSession.access_token)) {
console.log("refreshing token")
const newSession = await refreshToken(session.baseUrl, idnSession.refresh_token)
cookies.set("idnSession", JSON.stringify(newSession));
return Promise.resolve(newSession)
console.log('refreshing token');
const newSession = await refreshToken(session.baseUrl, idnSession.refresh_token);
cookies.set('idnSession', JSON.stringify(newSession));
return Promise.resolve(newSession);
} else {
console.log("token is good")
return Promise.resolve(idnSession)
console.log('token is good');
return Promise.resolve(idnSession);
}
}
function isJwtExpired(token: string): boolean {
try {
const decodedToken: any = jwt.decode(token, { complete: true });
if (!decodedToken || !decodedToken.payload || !decodedToken.payload.exp) {
// The token is missing the expiration claim ('exp') or is not a valid JWT.
return true; // Treat as expired for safety.
}
// Get the expiration timestamp from the token.
const expirationTimestamp = decodedToken.payload.exp;
// Get the current timestamp.
const currentTimestamp = Math.floor(Date.now() / 1000);
// Check if the token has expired.
return currentTimestamp >= expirationTimestamp;
const decodedToken = jwt.decode(token, { complete: true });
if (!decodedToken || !decodedToken.payload || !decodedToken.payload.exp) {
// The token is missing the expiration claim ('exp') or is not a valid JWT.
return true; // Treat as expired for safety.
}
// Get the expiration timestamp from the token.
const expirationTimestamp = decodedToken.payload.exp;
// Get the current timestamp.
const currentTimestamp = Math.floor(Date.now() / 1000);
// Check if the token has expired.
return currentTimestamp >= expirationTimestamp;
} catch (error) {
// An error occurred during decoding.
return true; // Treat as expired for safety.
// An error occurred during decoding.
return true; // Treat as expired for safety.
}
}
}

View File

@@ -0,0 +1,25 @@
import { HandleError } from '$lib/Errors.js';
import { createConfiguration } from '$lib/sailpoint/sdk';
import { getToken } from '$lib/utils/oauth';
import { json } from '@sveltejs/kit';
import { ManagedClustersBetaApi } from 'sailpoint-api-client';
/** @type {import('./$types').RequestHandler} */
export async function GET({ cookies, params }) {
try {
// Generic SDK setup
const session = JSON.parse(cookies.get('session')!);
const idnSession = await getToken(cookies);
const config = createConfiguration(session.baseUrl, idnSession.access_token);
// Route specific SDK call
let api = new ManagedClustersBetaApi(config);
const val = await api.getManagedCluster({ id: params.clusterID });
// console.log(val);
return json(val.data);
} catch (err) {
HandleError('issue arose during SDK source query', err);
}
}

View File

@@ -0,0 +1,23 @@
import { HandleError } from '$lib/Errors.js';
import { createConfiguration } from '$lib/sailpoint/sdk';
import { getToken } from '$lib/utils/oauth';
import { json } from '@sveltejs/kit';
import { Paginator, SearchApi, type Search } from 'sailpoint-api-client';
/** @type {import('./$types').RequestHandler} */
export async function POST({ request, cookies }) {
try {
const session = JSON.parse(cookies.get('session')!);
const idnSession = await getToken(cookies);
const searchJson = await request.json();
const config = createConfiguration(session.baseUrl, idnSession.access_token);
let api = new SearchApi(config);
let search: Search = searchJson;
const val = (await Paginator.paginateSearchApi(api, search, 100, 20000)).data;
//console.log(val)
return json(val);
} catch (err) {
HandleError('issue arose during SDK search query', err);
}
}

View File

@@ -0,0 +1,26 @@
import { HandleError } from '$lib/Errors.js';
import { createConfiguration } from '$lib/sailpoint/sdk';
import { getToken } from '$lib/utils/oauth';
import { json } from '@sveltejs/kit';
import { Paginator, SearchApi, type Search } from 'sailpoint-api-client';
/** @type {import('./$types').RequestHandler} */
export async function POST({ request, cookies, params }) {
try {
const session = JSON.parse(cookies.get('session')!);
const idnSession = await getToken(cookies);
const searchJson = await request.json();
const limit = Number(params.limit || 20000);
const increment = limit < 250 ? limit : 250;
const config = createConfiguration(session.baseUrl, idnSession.access_token);
let api = new SearchApi(config);
let search: Search = searchJson;
const val = (await Paginator.paginateSearchApi(api, search, increment, limit)).data;
//console.log(val)
return json(val);
} catch (err) {
HandleError('issue arose during SDK search query', err);
}
}

View File

@@ -0,0 +1,22 @@
import { HandleError } from '$lib/Errors.js';
import { createConfiguration } from '$lib/sailpoint/sdk';
import { getToken } from '$lib/utils/oauth';
import { json } from '@sveltejs/kit';
import { Paginator, SourcesApi, type SourcesApiGetSourceRequest } from 'sailpoint-api-client';
/** @type {import('./$types').RequestHandler} */
export async function GET({ cookies, params }) {
try {
const session = JSON.parse(cookies.get('session')!);
const idnSession = await getToken(cookies);
const config = createConfiguration(session.baseUrl, idnSession.access_token);
let api = new SourcesApi(config);
const val = await api.getSource({ id: params.sourceID });
// console.log(val);
return json(val.data);
} catch (err) {
HandleError('issue arose during SDK source query', err);
}
}

View File

@@ -0,0 +1,92 @@
import type { Data, FetchResponse, SourceEvents } from '$lib/Types.js';
import { json } from '@sveltejs/kit';
import type { EventDocument, Search, SearchDocument } from 'sailpoint-api-client';
export const GET = async ({ fetch }) => {
const sources = await (await fetch('/api/sailpoint/sources')).json();
const eventNames: string[] = [
'Aggregate Source Account Passed',
'Aggregate Source Account Started',
'Aggregate Source Entitlement Passed',
'Aggregate Source Entitlement Started',
];
const promises = [];
const allEvents: EventDocument[] = [];
for (const source of sources) {
for (const event of eventNames) {
const search: Search = {
indices: ['events'],
query: {
query: `target.name: "${source.name}" AND name:"${event}"`,
},
sort: ['created'],
};
promises.push(
fetch('/api/sailpoint/search/1', {
method: 'POST',
body: JSON.stringify(search),
})
.then((response: FetchResponse<SearchDocument>) => response.json())
.then((data: Data<SearchDocument>) => {
return data;
}),
);
}
}
await Promise.allSettled(promises).then((results) => {
for (const event of results) {
if (event.status == 'fulfilled' && event.value.length > 0) {
allEvents.push(event.value[0]);
}
}
});
const events = [];
for (const source of sources) {
const sourceEvents: SourceEvents = {
name: source.name,
accounts: { started: undefined, passed: undefined },
entitlements: { started: undefined, passed: undefined },
};
for (const event of allEvents) {
if (event.attributes!.sourceName === source.name) {
switch (event.technicalName) {
case 'SOURCE_ACCOUNT_AGGREGATE_STARTED':
if (!sourceEvents.accounts.started) {
sourceEvents.accounts.started = event || undefined;
}
break;
case 'SOURCE_ACCOUNT_AGGREGATE_PASSED':
if (!sourceEvents.accounts.passed) {
sourceEvents.accounts.passed = event || undefined;
}
break;
case 'SOURCE_ENTITLEMENT_AGGREGATE_STARTED':
if (!sourceEvents.entitlements.started) {
sourceEvents.entitlements.started = event || undefined;
}
break;
case 'SOURCE_ENTITLEMENT_AGGREGATE_PASSED':
if (!sourceEvents.entitlements.passed) {
sourceEvents.entitlements.passed = event || undefined;
}
break;
default:
break;
}
}
}
events.push(sourceEvents);
}
return json({ sources, events });
};

View File

@@ -0,0 +1,84 @@
import type { Data, FetchResponse, SourceEvents } from '$lib/Types.js';
import { json } from '@sveltejs/kit';
import type { EventDocument, Search, SearchDocument } from 'sailpoint-api-client';
export const GET = async ({ fetch, params }) => {
const source = await (await fetch(`/api/sailpoint/source/${params.sourceID}`)).json();
const eventNames: string[] = [
'Aggregate Source Account Passed',
'Aggregate Source Account Started',
'Aggregate Source Entitlement Passed',
'Aggregate Source Entitlement Started',
];
const promises = [];
const allEvents: EventDocument[] = [];
for (const event of eventNames) {
const search: Search = {
indices: ['events'],
query: {
query: `target.name: "${source.name}" AND name:"${event}"`,
},
sort: ['created'],
};
promises.push(
fetch('/api/sailpoint/search/1', {
method: 'POST',
body: JSON.stringify(search),
})
.then((response: FetchResponse<SearchDocument>) => response.json())
.then((data: Data<SearchDocument>) => {
return data;
}),
);
}
await Promise.allSettled(promises).then((results) => {
for (const event of results) {
if (event.status == 'fulfilled' && event.value.length > 0) {
allEvents.push(event.value[0]);
}
}
});
const sourceEvents: SourceEvents = {
name: source.name,
accounts: { started: undefined, passed: undefined },
entitlements: { started: undefined, passed: undefined },
};
for (const event of allEvents) {
if (event.attributes!.sourceName === source.name) {
switch (event.technicalName) {
case 'SOURCE_ACCOUNT_AGGREGATE_STARTED':
if (!sourceEvents.accounts.started) {
sourceEvents.accounts.started = event || undefined;
}
break;
case 'SOURCE_ACCOUNT_AGGREGATE_PASSED':
if (!sourceEvents.accounts.passed) {
sourceEvents.accounts.passed = event || undefined;
}
break;
case 'SOURCE_ENTITLEMENT_AGGREGATE_STARTED':
if (!sourceEvents.entitlements.started) {
sourceEvents.entitlements.started = event || undefined;
}
break;
case 'SOURCE_ENTITLEMENT_AGGREGATE_PASSED':
if (!sourceEvents.entitlements.passed) {
sourceEvents.entitlements.passed = event || undefined;
}
break;
default:
break;
}
}
}
return json({ source, sourceEvents });
};

View File

@@ -0,0 +1,21 @@
import { HandleError } from '$lib/Errors.js';
import { createConfiguration } from '$lib/sailpoint/sdk';
import { getToken } from '$lib/utils/oauth';
import { json } from '@sveltejs/kit';
import { Paginator, SourcesApi } from 'sailpoint-api-client';
/** @type {import('./$types').RequestHandler} */
export async function GET({ cookies }) {
try {
const session = JSON.parse(cookies.get('session')!);
const idnSession = await getToken(cookies);
const config = createConfiguration(session.baseUrl, idnSession.access_token);
let api = new SourcesApi(config);
const val = (await Paginator.paginate(api, api.listSources, { limit: 100 }, 10)).data;
//console.log(val)
return json(val);
} catch (err) {
HandleError('issue arose during SDK source query', err);
}
}

View File

@@ -0,0 +1,24 @@
import { HandleError } from '$lib/Errors.js';
import { createConfiguration } from '$lib/sailpoint/sdk';
import { getToken } from '$lib/utils/oauth';
import { json } from '@sveltejs/kit';
import { Paginator, SourcesApi } from 'sailpoint-api-client';
/** @type {import('./$types').RequestHandler} */
export async function GET({ cookies, params }) {
try {
const session = JSON.parse(cookies.get('session')!);
const idnSession = await getToken(cookies);
const limit = Number(params.limit || 20000);
const increment = limit < 250 ? limit : 250;
const config = createConfiguration(session.baseUrl, idnSession.access_token);
let api = new SourcesApi(config);
const val = (await Paginator.paginate(api, api.listSources, { limit }, increment)).data;
//console.log(val)
return json(val);
} catch (err) {
HandleError('issue arose during SDK source query', err);
}
}

View File

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View File

Before

Width:  |  Height:  |  Size: 259 KiB

After

Width:  |  Height:  |  Size: 259 KiB

View File

@@ -0,0 +1,21 @@
import adapter from '@sveltejs/adapter-node';
import { vitePreprocess } from '@sveltejs/kit/vite';
/** @type {import('@sveltejs/kit').Config} */
const config = {
extensions: ['.svelte'],
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
// for more information about preprocessors
preprocess: [vitePreprocess()],
kit: {
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
// If your environment is not supported or you settled on a specific environment, switch out the adapter.
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
adapter: adapter({ out: '../Sveltekit-Build/src' }),
csrf: {
checkOrigin: false
}
}
};
export default config;

View File

@@ -1,31 +1,28 @@
import { join } from 'path';
import type { Config } from 'tailwindcss';
// 1. Import the Skeleton plugin
import forms from '@tailwindcss/forms';
import typography from '@tailwindcss/typography';
import { skeleton } from '@skeletonlabs/tw-plugin';
const config = {
// 2. Opt for dark mode to be handled via the class method
export default {
darkMode: 'class',
content: [
'./src/**/*.{html,js,svelte,ts}',
// 3. Append the path to the Skeleton package
join(require.resolve('@skeletonlabs/skeleton'), '../**/*.{html,js,svelte,ts}'),
join(require.resolve('@skeletonlabs/skeleton'), '../**/*.{html,js,svelte,ts}')
],
theme: {
extend: {},
extend: {}
},
plugins: [
// 4. Append the Skeleton plugin (after other plugins)
forms,
typography,
skeleton({
themes: {
preset: [
{ name: 'wintry', enhancements: true },
{ name: 'skeleton', enhancements: true },
],
},
}),
],
{ name: 'skeleton', enhancements: true }
]
}
})
]
} satisfies Config;
export default config;

View File

@@ -0,0 +1,18 @@
{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"moduleResolution": "bundler"
}
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
//
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
// from the referenced tsconfig.json - TypeScript does not merge them in
}

View File

@@ -0,0 +1,14 @@
import { purgeCss } from 'vite-plugin-tailwind-purgecss';
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vitest/config';
export default defineConfig({
plugins: [sveltekit(), purgeCss()],
test: {
include: ['src/**/*.{test,spec}.{js,ts}']
},
server: {
port: 3000,
origin: 'http://localhost:3000'
}
});

View File

@@ -0,0 +1,8 @@
{
"name": "built-app",
"version": "0.0.1",
"scripts": {
"start": "node ./src"
},
"type": "module"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
.sliding-text.svelte-1fdnh10.svelte-1fdnh10.svelte-1fdnh10{display:inline-block;position:relative;line-height:1em;height:1em}.sliding-text.svelte-1fdnh10>span.svelte-1fdnh10.svelte-1fdnh10{height:1em;display:inline-block;overflow-y:hidden}.sliding-text.svelte-1fdnh10>span.svelte-1fdnh10>span.svelte-1fdnh10{text-align:center;transition:all var(--interval) var(--ease);position:relative;height:100%;white-space:pre;top:calc(var(--index) * -2em)}.skills.svelte-1285lhc{display:flex;justify-items:start;align-items:center;flex-wrap:wrap}.custom-skill{display:inline-block;text-align:center}

View File

@@ -0,0 +1 @@
.progress-bar.svelte-sfm816{padding-top:calc(50vh - 4.5rem - 200px);padding-left:calc(50% - 4.5rem)}

View File

@@ -0,0 +1 @@
.animIndeterminate.svelte-meqa4r{transform-origin:0% 50%;animation:svelte-meqa4r-animIndeterminate 2s infinite linear}@keyframes svelte-meqa4r-animIndeterminate{0%{transform:translate(0) scaleX(0)}40%{transform:translate(0) scaleX(.4)}to{transform:translate(100%) scaleX(.5)}}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
.progress-bar.svelte-sfm816{padding-top:calc(50vh - 4.5rem - 200px);padding-left:calc(50% - 4.5rem)}

View File

@@ -0,0 +1 @@
.sliding-text.svelte-1fdnh10.svelte-1fdnh10.svelte-1fdnh10{display:inline-block;position:relative;line-height:1em;height:1em}.sliding-text.svelte-1fdnh10>span.svelte-1fdnh10.svelte-1fdnh10{height:1em;display:inline-block;overflow-y:hidden}.sliding-text.svelte-1fdnh10>span.svelte-1fdnh10>span.svelte-1fdnh10{text-align:center;transition:all var(--interval) var(--ease);position:relative;height:100%;white-space:pre;top:calc(var(--index) * -2em)}.skills.svelte-1285lhc{display:flex;justify-items:start;align-items:center;flex-wrap:wrap}.custom-skill{display:inline-block;text-align:center}

View File

@@ -0,0 +1,3 @@
import{a3 as X,a4 as z,s as Y,e as x,i as B,z as O,d as v,v as Z,w as $,x as V,y as W,f as H,l as M,a as J,g as L,h as N,m as j,c as R,j as C,A as E,u as ee,B as te,n as P,a5 as ae,D as ne,H as oe,F as le}from"./scheduler.10bc074a.js";import{S as ie,i as re}from"./index.7b3d626a.js";import{w as se}from"./index.09b1afef.js";const ce=se(void 0);function ue(n,e){if(!window.isSecureContext){console.error("Clipboard action failed: app not running in secure context, see: https://developer.mozilla.org/en-US/docs/Web/API/Clipboard");return}const t=()=>{n.dispatchEvent(new CustomEvent("copyComplete"))},a=()=>{if(typeof e=="object"){if("element"in e){const l=document.querySelector(`[data-clipboard="${e.element}"]`);if(!l)throw new Error(`Missing HTMLElement with an attribute of [data-clipboard="${e.element}"]`);D(l.innerHTML,"text/html").then(t);return}if("input"in e){const l=document.querySelector(`[data-clipboard="${e.input}"]`);if(!l)throw new Error(`Missing HTMLInputElement with an attribute of [data-clipboard="${e.input}"]`);D(l.value).then(t);return}}D(e).then(t)};return n.addEventListener("click",a),{update(l){e=l},destroy(){n.removeEventListener("click",a)}}}async function D(n,e="text/plain"){navigator.clipboard.write?await navigator.clipboard.write([new ClipboardItem({[e]:new Blob([n],{type:e}),"text/plain":new Blob([n],{type:"text/plain"})})]):await new Promise(t=>{t(navigator.clipboard.writeText(String(n)))})}function Q(n){const e=n-1;return e*e*e+1}function Ce(n,{delay:e=0,duration:t=400,easing:a=X}={}){const l=+getComputedStyle(n).opacity;return{delay:e,duration:t,easing:a,css:r=>`opacity: ${r*l}`}}function ve(n,{delay:e=0,duration:t=400,easing:a=Q,x:l=0,y:r=0,opacity:y=0}={}){const i=getComputedStyle(n),b=+i.opacity,s=i.transform==="none"?"":i.transform,u=b*(1-y),[p,g]=z(l),[m,d]=z(r);return{delay:e,duration:t,easing:a,css:(_,k)=>`
transform: ${s} translate(${(1-_)*p}${g}, ${(1-_)*m}${d});
opacity: ${b-u*k}`}}function Ee(n,{delay:e=0,duration:t=400,easing:a=Q,axis:l="y"}={}){const r=getComputedStyle(n),y=+r.opacity,i=l==="y"?"height":"width",b=parseFloat(r[i]),s=l==="y"?["top","bottom"]:["left","right"],u=s.map(c=>`${c[0].toUpperCase()}${c.slice(1)}`),p=parseFloat(r[`padding${u[0]}`]),g=parseFloat(r[`padding${u[1]}`]),m=parseFloat(r[`margin${u[0]}`]),d=parseFloat(r[`margin${u[1]}`]),_=parseFloat(r[`border${u[0]}Width`]),k=parseFloat(r[`border${u[1]}Width`]);return{delay:e,duration:t,easing:a,css:c=>`overflow: hidden;opacity: ${Math.min(c*20,1)*y};${i}: ${c*b}px;padding-${s[0]}: ${c*p}px;padding-${s[1]}: ${c*g}px;margin-${s[0]}: ${c*m}px;margin-${s[1]}: ${c*d}px;border-${s[0]}-width: ${c*_}px;border-${s[1]}-width: ${c*k}px;`}}function we(n,e){const{transition:t,params:a,enabled:l}=e;return l?t(n,a):"duration"in a?t(n,{duration:0}):{duration:0}}function G(n){let e,t,a,l=K(n[0])+"",r,y,i,b=(n[7]?n[4]:n[3])+"",s,u,p,g,m,d,_,k,c,F;function S(o,f){return o[6]?fe:de}let w=S(n),h=w(n);return{c(){e=H("div"),t=H("header"),a=H("span"),r=M(l),y=J(),i=H("button"),s=M(b),g=J(),m=H("pre"),d=H("code"),h.c(),this.h()},l(o){e=L(o,"DIV",{class:!0,"data-testid":!0});var f=N(e);t=L(f,"HEADER",{class:!0});var T=N(t);a=L(T,"SPAN",{class:!0});var U=N(a);r=j(U,l),U.forEach(v),y=R(T),i=L(T,"BUTTON",{class:!0});var A=N(i);s=j(A,b),A.forEach(v),T.forEach(v),g=R(f),m=L(f,"PRE",{class:!0});var I=N(m);d=L(I,"CODE",{class:!0});var q=N(d);h.l(q),q.forEach(v),I.forEach(v),f.forEach(v),this.h()},h(){C(a,"class","codeblock-language"),C(i,"class",u="codeblock-btn "+n[2]),C(t,"class","codeblock-header "+he),C(d,"class",_="codeblock-code language-"+n[0]+" lineNumbers"),C(m,"class","codeblock-pre "+pe),C(e,"class",k="codeblock "+n[8]),C(e,"data-testid","codeblock")},m(o,f){B(o,e,f),E(e,t),E(t,a),E(a,r),E(t,y),E(t,i),E(i,s),E(e,g),E(e,m),E(m,d),h.m(d,null),c||(F=[ee(i,"click",n[9]),te(p=ue.call(null,i,n[1]))],c=!0)},p(o,f){f&1&&l!==(l=K(o[0])+"")&&P(r,l),f&152&&b!==(b=(o[7]?o[4]:o[3])+"")&&P(s,b),f&4&&u!==(u="codeblock-btn "+o[2])&&C(i,"class",u),p&&ae(p.update)&&f&2&&p.update.call(null,o[1]),w===(w=S(o))&&h?h.p(o,f):(h.d(1),h=w(o),h&&(h.c(),h.m(d,null))),f&1&&_!==(_="codeblock-code language-"+o[0]+" lineNumbers")&&C(d,"class",_),f&256&&k!==(k="codeblock "+o[8])&&C(e,"class",k)},d(o){o&&v(e),h.d(),c=!1,ne(F)}}}function de(n){let e=n[1].trim()+"",t;return{c(){t=M(e)},l(a){t=j(a,e)},m(a,l){B(a,t,l)},p(a,l){l&2&&e!==(e=a[1].trim()+"")&&P(t,e)},d(a){a&&v(t)}}}function fe(n){let e,t;return{c(){e=new oe(!1),t=x(),this.h()},l(a){e=le(a,!1),t=x(),this.h()},h(){e.a=t},m(a,l){e.m(n[5],a,l),B(a,t,l)},p(a,l){l&32&&e.p(a[5])},d(a){a&&(v(t),e.d())}}}function be(n){let e,t=n[0]&&n[1]&&G(n);return{c(){t&&t.c(),e=x()},l(a){t&&t.l(a),e=x()},m(a,l){t&&t.m(a,l),B(a,e,l)},p(a,[l]){a[0]&&a[1]?t?t.p(a,l):(t=G(a),t.c(),t.m(e.parentNode,e)):t&&(t.d(1),t=null)},i:O,o:O,d(a){a&&v(e),t&&t.d(a)}}}const me="overflow-hidden shadow",he="text-xs text-white/50 uppercase flex justify-between items-center p-2 pl-4",pe="whitespace-pre-wrap break-all p-4 pt-1";function K(n){return n==="js"?"javascript":n==="ts"?"typescript":n==="shell"?"terminal":n}function _e(n,e,t){let a,l;Z(n,ce,o=>t(17,l=o));const r=$();let{language:y="plaintext"}=e,{code:i=""}=e,{lineNumbers:b=!1}=e,{background:s="bg-neutral-900/90"}=e,{blur:u=""}=e,{text:p="text-sm"}=e,{color:g="text-white"}=e,{rounded:m="rounded-container-token"}=e,{shadow:d="shadow"}=e,{button:_="btn btn-sm variant-soft !text-white"}=e,{buttonLabel:k="Copy"}=e,{buttonCopied:c="👍"}=e,F=!1,S=i,w=!1;function h(){t(7,w=!0),setTimeout(()=>{t(7,w=!1)},2e3),r("copy")}return n.$$set=o=>{t(19,e=V(V({},e),W(o))),"language"in o&&t(0,y=o.language),"code"in o&&t(1,i=o.code),"lineNumbers"in o&&t(10,b=o.lineNumbers),"background"in o&&t(11,s=o.background),"blur"in o&&t(12,u=o.blur),"text"in o&&t(13,p=o.text),"color"in o&&t(14,g=o.color),"rounded"in o&&t(15,m=o.rounded),"shadow"in o&&t(16,d=o.shadow),"button"in o&&t(2,_=o.button),"buttonLabel"in o&&t(3,k=o.buttonLabel),"buttonCopied"in o&&t(4,c=o.buttonCopied)},n.$$.update=()=>{n.$$.dirty&131075&&l!==void 0&&(t(5,S=l.highlight(i,{language:y}).value.trim()),t(6,F=!0)),n.$$.dirty&1056&&b&&(t(5,S=S.replace(/^/gm,()=>'<span class="line"></span> ')),t(6,F=!0)),t(8,a=`${me} ${s} ${u} ${p} ${g} ${m} ${d} ${e.class??""}`)},e=W(e),[y,i,_,k,c,S,F,w,a,h,b,s,u,p,g,m,d,l]}class Se extends ie{constructor(e){super(),re(this,e,_e,be,Y,{language:0,code:1,lineNumbers:10,background:11,blur:12,text:13,color:14,rounded:15,shadow:16,button:2,buttonLabel:3,buttonCopied:4})}}export{Se as C,ve as a,we as d,Ce as f,Ee as s};

View File

@@ -0,0 +1 @@
import{s as N,H as Q,e as M,a as R,f as z,T as I,U as X,F as Y,d as k,c as Z,g as B,h as T,V as H,j as c,A as S,i as P,u as w,z as j,D as x,v as p,o as $,x as q,y as V,W as tt,E as C}from"./scheduler.10bc074a.js";import{S as et,i as it}from"./index.7b3d626a.js";import{s as st,m as F,a as U,g as at,b as lt}from"./ProgressBar.svelte_svelte_type_style_lang.ae9fcbec.js";function ct(t){let s,a=`<script nonce="%sveltekit.nonce%">(${st.toString()})();<\/script>`,o,f,i,u,h,g,b,r,_,d,m,v;return{c(){s=new Q(!1),o=M(),f=R(),i=z("div"),u=z("div"),h=I("svg"),g=I("path"),this.h()},l(l){const n=X("svelte-gewkj4",document.head);s=Y(n,!1),o=M(),n.forEach(k),f=Z(l),i=B(l,"DIV",{class:!0,role:!0,"aria-label":!0,"aria-checked":!0,title:!0,tabindex:!0});var L=T(i);u=B(L,"DIV",{class:!0});var D=T(u);h=H(D,"svg",{class:!0,xmlns:!0,viewBox:!0});var y=T(h);g=H(y,"path",{d:!0}),T(g).forEach(k),y.forEach(k),D.forEach(k),L.forEach(k),this.h()},h(){s.a=o,c(g,"d",b=t[1]?t[5].sun:t[5].moon),c(h,"class",r="lightswitch-icon "+t[2]),c(h,"xmlns","http://www.w3.org/2000/svg"),c(h,"viewBox","0 0 512 512"),c(u,"class",_="lightswitch-thumb "+t[3]),c(i,"class",d="lightswitch-track "+t[4]),c(i,"role","switch"),c(i,"aria-label","Light Switch"),c(i,"aria-checked",t[1]),c(i,"title",t[0]),c(i,"tabindex","0")},m(l,n){s.m(a,document.head),S(document.head,o),P(l,f,n),P(l,i,n),S(i,u),S(u,h),S(h,g),m||(v=[w(i,"click",t[6]),w(i,"click",t[19]),w(i,"keydown",ut),w(i,"keydown",t[20]),w(i,"keyup",t[21]),w(i,"keypress",t[22])],m=!0)},p(l,[n]){n&2&&b!==(b=l[1]?l[5].sun:l[5].moon)&&c(g,"d",b),n&4&&r!==(r="lightswitch-icon "+l[2])&&c(h,"class",r),n&8&&_!==(_="lightswitch-thumb "+l[3])&&c(u,"class",_),n&16&&d!==(d="lightswitch-track "+l[4])&&c(i,"class",d),n&2&&c(i,"aria-checked",l[1]),n&1&&c(i,"title",l[0])},i:j,o:j,d(l){l&&(s.d(),k(f),k(i)),k(o),m=!1,x(v)}}}const rt="cursor-pointer",nt="aspect-square scale-[0.8] flex justify-center items-center",ht="w-[70%] aspect-square";function ut(t){["Enter","Space"].includes(t.code)&&(t.preventDefault(),t.currentTarget.click())}function ot(t,s,a){let o,f,i,u,h,g,b,r;p(t,F,e=>a(1,r=e));let{title:_="Toggle light or dark mode."}=s,{bgLight:d="bg-surface-50"}=s,{bgDark:m="bg-surface-900"}=s,{fillLight:v="fill-surface-50"}=s,{fillDark:l="fill-surface-900"}=s,{width:n="w-12"}=s,{height:L="h-6"}=s,{ring:D="ring-[1px] ring-surface-500/30"}=s,{rounded:y="rounded-token"}=s;const E="transition-all duration-[200ms]",A={sun:"M361.5 1.2c5 2.1 8.6 6.6 9.6 11.9L391 121l107.9 19.8c5.3 1 9.8 4.6 11.9 9.6s1.5 10.7-1.6 15.2L446.9 256l62.3 90.3c3.1 4.5 3.7 10.2 1.6 15.2s-6.6 8.6-11.9 9.6L391 391 371.1 498.9c-1 5.3-4.6 9.8-9.6 11.9s-10.7 1.5-15.2-1.6L256 446.9l-90.3 62.3c-4.5 3.1-10.2 3.7-15.2 1.6s-8.6-6.6-9.6-11.9L121 391 13.1 371.1c-5.3-1-9.8-4.6-11.9-9.6s-1.5-10.7 1.6-15.2L65.1 256 2.8 165.7c-3.1-4.5-3.7-10.2-1.6-15.2s6.6-8.6 11.9-9.6L121 121 140.9 13.1c1-5.3 4.6-9.8 9.6-11.9s10.7-1.5 15.2 1.6L256 65.1 346.3 2.8c4.5-3.1 10.2-3.7 15.2-1.6zM352 256c0 53-43 96-96 96s-96-43-96-96s43-96 96-96s96 43 96 96zm32 0c0-70.7-57.3-128-128-128s-128 57.3-128 128s57.3 128 128 128s128-57.3 128-128z",moon:"M223.5 32C100 32 0 132.3 0 256S100 480 223.5 480c60.6 0 115.5-24.2 155.8-63.4c5-4.9 6.3-12.5 3.1-18.7s-10.1-9.7-17-8.5c-9.8 1.7-19.8 2.6-30.1 2.6c-96.9 0-175.5-78.8-175.5-176c0-65.8 36-123.1 89.3-153.3c6.1-3.5 9.2-10.5 7.7-17.3s-7.3-11.9-14.3-12.5c-6.3-.5-12.6-.8-19-.8z"};function K(){tt(F,r=!r,r),lt(r),U(r)}$(()=>{"modeCurrent"in localStorage||U(at())});function O(e){C.call(this,t,e)}function W(e){C.call(this,t,e)}function G(e){C.call(this,t,e)}function J(e){C.call(this,t,e)}return t.$$set=e=>{a(24,s=q(q({},s),V(e))),"title"in e&&a(0,_=e.title),"bgLight"in e&&a(7,d=e.bgLight),"bgDark"in e&&a(8,m=e.bgDark),"fillLight"in e&&a(9,v=e.fillLight),"fillDark"in e&&a(10,l=e.fillDark),"width"in e&&a(11,n=e.width),"height"in e&&a(12,L=e.height),"ring"in e&&a(13,D=e.ring),"rounded"in e&&a(14,y=e.rounded)},t.$$.update=()=>{t.$$.dirty&386&&a(18,o=r===!0?d:m),t.$$.dirty&386&&a(17,f=r===!0?m:d),t.$$.dirty&2&&a(16,i=r===!0?"translate-x-[100%]":""),t.$$.dirty&1538&&a(15,u=r===!0?v:l),a(4,h=`${rt} ${E} ${n} ${L} ${D} ${y} ${o} ${s.class??""}`),t.$$.dirty&217088&&a(3,g=`${nt} ${E} ${L} ${y} ${f} ${i}`),t.$$.dirty&32768&&a(2,b=`${ht} ${u}`)},s=V(s),[_,r,b,g,h,A,K,d,m,v,l,n,L,D,y,u,i,f,o,O,W,G,J]}class mt extends et{constructor(s){super(),it(this,s,ot,ct,N,{title:0,bgLight:7,bgDark:8,fillLight:9,fillDark:10,width:11,height:12,ring:13,rounded:14})}}export{mt as L};

View File

@@ -0,0 +1 @@
import{s as i,f as m,g as l,h as c,d as o,j as p,i as _,z as f}from"./scheduler.10bc074a.js";import{S as d,i as u,b as g,d as h,m as v,a as $,t as y,e as P}from"./index.7b3d626a.js";import"./ProgressBar.svelte_svelte_type_style_lang.ae9fcbec.js";import{P as k}from"./Table.f5db4492.js";function b(n){let e,s,r;return s=new k({props:{stroke:100,meter:"stroke-primary-500",track:"stroke-primary-500/30",class:"progress-bar"}}),{c(){e=m("div"),g(s.$$.fragment),this.h()},l(t){e=l(t,"DIV",{class:!0});var a=c(e);h(s.$$.fragment,a),a.forEach(o),this.h()},h(){p(e,"class","progress-bar svelte-sfm816")},m(t,a){_(t,e,a),v(s,e,null),r=!0},p:f,i(t){r||($(s.$$.fragment,t),r=!0)},o(t){y(s.$$.fragment,t),r=!1},d(t){t&&o(e),P(s)}}}class w extends d{constructor(e){super(),u(this,e,null,b,i,{})}}export{w as P};

View File

@@ -0,0 +1 @@
import{w as M,r as S}from"./index.09b1afef.js";import{a6 as P}from"./scheduler.10bc074a.js";const l={};function h(e){return e==="local"?localStorage:sessionStorage}function i(e,t,s){const r=(s==null?void 0:s.serializer)??JSON,m=(s==null?void 0:s.storage)??"local";function u(n,c){h(m).setItem(n,r.stringify(c))}if(!l[e]){const n=M(t,o=>{const a=h(m).getItem(e);a&&o(r.parse(a));{const g=d=>{d.key===e&&o(d.newValue?r.parse(d.newValue):null)};return window.addEventListener("storage",g),()=>window.removeEventListener("storage",g)}}),{subscribe:c,set:f}=n;l[e]={set(o){u(e,o),f(o)},update(o){const a=o(P(n));u(e,a),f(a)},subscribe:c}}return l[e]}const L=i("modeOsPrefers",!1),v=i("modeUserPrefers",void 0),p=i("modeCurrent",!1);function C(){const e=window.matchMedia("(prefers-color-scheme: light)").matches;return L.set(e),e}function b(e){v.set(e)}function I(e){const t=document.documentElement.classList,s="dark";e===!0?t.remove(s):t.add(s),p.set(e)}function O(){const e=document.documentElement.classList,t=localStorage.getItem("modeUserPrefers")==="false",s=!("modeUserPrefers"in localStorage),r=window.matchMedia("(prefers-color-scheme: dark)").matches;t||s&&r?e.add("dark"):e.remove("dark")}const w="(prefers-reduced-motion: reduce)";function E(){return window.matchMedia(w).matches}const R=S(E(),e=>{{const t=r=>{e(r.matches)},s=window.matchMedia(w);return s.addEventListener("change",t),()=>{s.removeEventListener("change",t)}}});export{I as a,b,C as g,i as l,p as m,R as p,O as s};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More