@stackoverflow/backstage-plugin-stack-overflow-teams 1.6.1 → 1.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/StackOverflowAPI.esm.js +125 -0
- package/dist/api/StackOverflowAPI.esm.js.map +1 -0
- package/dist/components/StackOverflow/StackOverflowMe.esm.js +125 -0
- package/dist/components/StackOverflow/StackOverflowMe.esm.js.map +1 -0
- package/dist/components/StackOverflow/StackOverflowPostQuestionModal.esm.js +803 -0
- package/dist/components/StackOverflow/StackOverflowPostQuestionModal.esm.js.map +1 -0
- package/dist/components/StackOverflow/StackOverflowPosts.esm.js +444 -0
- package/dist/components/StackOverflow/StackOverflowPosts.esm.js.map +1 -0
- package/dist/components/StackOverflow/StackOverflowSearchResultListItem.esm.js +175 -0
- package/dist/components/StackOverflow/StackOverflowSearchResultListItem.esm.js.map +1 -0
- package/dist/components/StackOverflow/StackOverflowTags.esm.js +127 -0
- package/dist/components/StackOverflow/StackOverflowTags.esm.js.map +1 -0
- package/dist/components/StackOverflow/StackOverflowUsers.esm.js +226 -0
- package/dist/components/StackOverflow/StackOverflowUsers.esm.js.map +1 -0
- package/dist/components/StackOverflow/TiptapEditor.esm.js +312 -0
- package/dist/components/StackOverflow/TiptapEditor.esm.js.map +1 -0
- package/dist/components/StackOverflow/hooks/useStackOverflowData.esm.js +128 -0
- package/dist/components/StackOverflow/hooks/useStackOverflowData.esm.js.map +1 -0
- package/dist/components/StackOverflow/hooks/useStackOverflowSearch.esm.js +53 -0
- package/dist/components/StackOverflow/hooks/useStackOverflowSearch.esm.js.map +1 -0
- package/dist/components/StackOverflow/hooks/useStackOverflowStyles.esm.js +39 -0
- package/dist/components/StackOverflow/hooks/useStackOverflowStyles.esm.js.map +1 -0
- package/dist/components/StackOverflowAuth/StackAuthCallback.esm.js +48 -0
- package/dist/components/StackOverflowAuth/StackAuthCallback.esm.js.map +1 -0
- package/dist/components/StackOverflowAuth/StackAuthFailed.esm.js +38 -0
- package/dist/components/StackOverflowAuth/StackAuthFailed.esm.js.map +1 -0
- package/dist/components/StackOverflowAuth/StackAuthLoading.esm.js +22 -0
- package/dist/components/StackOverflowAuth/StackAuthLoading.esm.js.map +1 -0
- package/dist/components/StackOverflowAuth/StackAuthStart.esm.js +238 -0
- package/dist/components/StackOverflowAuth/StackAuthStart.esm.js.map +1 -0
- package/dist/components/StackOverflowAuth/StackAuthSuccess.esm.js +40 -0
- package/dist/components/StackOverflowAuth/StackAuthSuccess.esm.js.map +1 -0
- package/dist/icons/LogoutIcon.esm.js +24 -0
- package/dist/icons/LogoutIcon.esm.js.map +1 -0
- package/dist/icons/StackOverflowIcon.esm.js +27 -0
- package/dist/icons/StackOverflowIcon.esm.js.map +1 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.esm.js +19 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/package.json.esm.js +6 -0
- package/dist/package.json.esm.js.map +1 -0
- package/dist/pages/StackOverflowHub.esm.js +138 -0
- package/dist/pages/StackOverflowHub.esm.js.map +1 -0
- package/dist/pages/StackOverflowTeamsPage.esm.js +43 -0
- package/dist/pages/StackOverflowTeamsPage.esm.js.map +1 -0
- package/dist/pages/index.esm.js +3 -0
- package/dist/pages/index.esm.js.map +1 -0
- package/dist/plugin.esm.js +27 -0
- package/dist/plugin.esm.js.map +1 -0
- package/dist/routes.esm.js +8 -0
- package/dist/routes.esm.js.map +1 -0
- package/dist/utils/decodeHtml.esm.js +8 -0
- package/dist/utils/decodeHtml.esm.js.map +1 -0
- package/dist/utils/getTimeAgo.esm.js +30 -0
- package/dist/utils/getTimeAgo.esm.js.map +1 -0
- package/package.json +13 -7
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { createApiRef } from '@backstage/core-plugin-api';
|
|
2
|
+
|
|
3
|
+
const stackoverflowteamsApiRef = createApiRef({
|
|
4
|
+
id: "plugin.stackoverflowteams.api"
|
|
5
|
+
});
|
|
6
|
+
const createStackOverflowApi = (discoveryApi, fetchApi) => {
|
|
7
|
+
const getBaseUrl = async () => discoveryApi.getBaseUrl("stack-overflow-teams");
|
|
8
|
+
const requestAPI = async (endpoint, method = "GET", body, params) => {
|
|
9
|
+
const baseUrl = await getBaseUrl();
|
|
10
|
+
const queryString = params ? `?${params.join("&")}` : "";
|
|
11
|
+
const url = `${baseUrl}/${endpoint}${queryString}`;
|
|
12
|
+
const response = await fetchApi.fetch(url, {
|
|
13
|
+
method,
|
|
14
|
+
credentials: "include",
|
|
15
|
+
headers: { "Content-Type": "application/json" },
|
|
16
|
+
body: body ? JSON.stringify(body) : void 0
|
|
17
|
+
});
|
|
18
|
+
if (!response.ok) {
|
|
19
|
+
const errorResponse = await response.json();
|
|
20
|
+
throw new Error(errorResponse.error || `Request failed: ${response.statusText}`);
|
|
21
|
+
}
|
|
22
|
+
return response.json();
|
|
23
|
+
};
|
|
24
|
+
const buildQuestionParams = (filter) => {
|
|
25
|
+
const params = [];
|
|
26
|
+
if (filter?.sort) {
|
|
27
|
+
params.push(`sort=${filter.sort}`);
|
|
28
|
+
}
|
|
29
|
+
if (filter?.order) {
|
|
30
|
+
params.push(`order=${filter.order}`);
|
|
31
|
+
}
|
|
32
|
+
if (filter?.isAnswered !== void 0) {
|
|
33
|
+
params.push(`isAnswered=${filter.isAnswered}`);
|
|
34
|
+
}
|
|
35
|
+
if (filter?.page !== void 0) {
|
|
36
|
+
params.push(`page=${filter.page}`);
|
|
37
|
+
}
|
|
38
|
+
if (filter?.pageSize !== void 0) {
|
|
39
|
+
params.push(`pageSize=${filter.pageSize}`);
|
|
40
|
+
}
|
|
41
|
+
return params;
|
|
42
|
+
};
|
|
43
|
+
return {
|
|
44
|
+
search: (query, page) => {
|
|
45
|
+
const body = { query };
|
|
46
|
+
if (page !== void 0) {
|
|
47
|
+
body.page = page;
|
|
48
|
+
}
|
|
49
|
+
return requestAPI("search", "POST", body);
|
|
50
|
+
},
|
|
51
|
+
getQuestions: (filter) => {
|
|
52
|
+
const params = buildQuestionParams(filter);
|
|
53
|
+
return requestAPI("questions", "GET", void 0, params.length > 0 ? params : void 0);
|
|
54
|
+
},
|
|
55
|
+
getTags: (search) => {
|
|
56
|
+
const params = search ? [`search=${encodeURIComponent(search)}`] : void 0;
|
|
57
|
+
return requestAPI("tags", "GET", void 0, params);
|
|
58
|
+
},
|
|
59
|
+
getUsers: () => requestAPI("users"),
|
|
60
|
+
getMe: () => requestAPI("me"),
|
|
61
|
+
getBaseUrl: async () => {
|
|
62
|
+
const response = await requestAPI("baseurl");
|
|
63
|
+
return response.SOInstance;
|
|
64
|
+
},
|
|
65
|
+
getTeamName: async () => {
|
|
66
|
+
const response = await requestAPI("baseurl");
|
|
67
|
+
return response.teamName;
|
|
68
|
+
},
|
|
69
|
+
postQuestion: (title, body, tags) => requestAPI("questions", "POST", { title, body, tags }),
|
|
70
|
+
startAuth: async () => {
|
|
71
|
+
const data = await requestAPI("auth/start");
|
|
72
|
+
return data.authUrl;
|
|
73
|
+
},
|
|
74
|
+
completeAuth: async (code, state) => {
|
|
75
|
+
await requestAPI("callback", "GET", void 0, [
|
|
76
|
+
`code=${encodeURIComponent(code)}`,
|
|
77
|
+
`state=${encodeURIComponent(state)}`
|
|
78
|
+
]);
|
|
79
|
+
},
|
|
80
|
+
getAuthStatus: async () => {
|
|
81
|
+
try {
|
|
82
|
+
await requestAPI("authStatus");
|
|
83
|
+
return true;
|
|
84
|
+
} catch {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
logout: async () => {
|
|
89
|
+
try {
|
|
90
|
+
await requestAPI("logout", "POST");
|
|
91
|
+
return true;
|
|
92
|
+
} catch {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
submitAccessToken: async (token) => {
|
|
97
|
+
try {
|
|
98
|
+
await requestAPI("auth/token", "POST", { accessToken: token });
|
|
99
|
+
return true;
|
|
100
|
+
} catch {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
// Convenience methods for common filtering scenarios
|
|
105
|
+
getActiveQuestions: (page) => {
|
|
106
|
+
const params = buildQuestionParams({ sort: "activity", order: "desc", page });
|
|
107
|
+
return requestAPI("questions", "GET", void 0, params);
|
|
108
|
+
},
|
|
109
|
+
getNewestQuestions: (page) => {
|
|
110
|
+
const params = buildQuestionParams({ sort: "creation", order: "desc", page });
|
|
111
|
+
return requestAPI("questions", "GET", void 0, params);
|
|
112
|
+
},
|
|
113
|
+
getTopScoredQuestions: (page) => {
|
|
114
|
+
const params = buildQuestionParams({ sort: "score", order: "desc", page });
|
|
115
|
+
return requestAPI("questions", "GET", void 0, params);
|
|
116
|
+
},
|
|
117
|
+
getUnansweredQuestions: (page) => {
|
|
118
|
+
const params = buildQuestionParams({ isAnswered: false, sort: "creation", order: "desc", page });
|
|
119
|
+
return requestAPI("questions", "GET", void 0, params);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export { createStackOverflowApi, stackoverflowteamsApiRef };
|
|
125
|
+
//# sourceMappingURL=StackOverflowAPI.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StackOverflowAPI.esm.js","sources":["../../src/api/StackOverflowAPI.ts"],"sourcesContent":["import {\n createApiRef,\n DiscoveryApi,\n FetchApi,\n} from '@backstage/core-plugin-api';\nimport { Question, Tag, User, PaginatedResponse } from '../api';\n\nexport const stackoverflowteamsApiRef = createApiRef<StackOverflowAPI>({\n id: 'plugin.stackoverflowteams.api',\n});\n\ntype ApiResponse<T> = PaginatedResponse<T>;\n\ninterface BaseUrlResponse {\n SOInstance: string;\n teamName: string\n}\n\n// Enhanced interface for questions filter options\ninterface QuestionsFilter {\n sort?: 'activity' | 'creation' | 'score';\n order?: 'asc' | 'desc';\n isAnswered?: boolean;\n page?: number;\n pageSize?: number;\n}\n\nexport interface StackOverflowAPI {\n search(query: string, page?: number): Promise<any>;\n getQuestions(filter?: QuestionsFilter): Promise<ApiResponse<Question>>;\n getTags(search?: string): Promise<ApiResponse<Tag>>;\n getUsers(): Promise<ApiResponse<User>>;\n getMe(): Promise<User>;\n getBaseUrl(): Promise<string>;\n getTeamName(): Promise<string>;\n postQuestion(title: string, body: string, tags: string[]): Promise<Question>;\n startAuth(): Promise<string>;\n completeAuth(code: string, state: string): Promise<void>;\n getAuthStatus: () => Promise<boolean>;\n logout: () => Promise<boolean>;\n submitAccessToken: (token: string) => Promise<boolean>;\n \n // Convenience methods for common filtering scenarios\n getActiveQuestions(page?: number): Promise<ApiResponse<Question>>;\n getNewestQuestions(page?: number): Promise<ApiResponse<Question>>;\n getTopScoredQuestions(page?: number): Promise<ApiResponse<Question>>;\n getUnansweredQuestions(page?: number): Promise<ApiResponse<Question>>;\n}\n\nexport const createStackOverflowApi = (\n discoveryApi: DiscoveryApi,\n fetchApi: FetchApi,\n): StackOverflowAPI => {\n const getBaseUrl = async () => discoveryApi.getBaseUrl('stack-overflow-teams');\n\n const requestAPI = async <T>(\n endpoint: string,\n method: 'GET' | 'POST' = 'GET',\n body?: Record<string, unknown>,\n params?: string[],\n ): Promise<T> => {\n const baseUrl = await getBaseUrl();\n const queryString = params ? `?${params.join('&')}` : '';\n const url = `${baseUrl}/${endpoint}${queryString}`;\n \n const response = await fetchApi.fetch(url, {\n method,\n credentials: 'include',\n headers: { 'Content-Type': 'application/json' },\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n const errorResponse = await response.json();\n throw new Error(errorResponse.error || `Request failed: ${response.statusText}`);\n }\n\n return response.json();\n };\n\n const buildQuestionParams = (filter?: QuestionsFilter): string[] => {\n const params: string[] = [];\n \n if (filter?.sort) {\n params.push(`sort=${filter.sort}`);\n }\n \n if (filter?.order) {\n params.push(`order=${filter.order}`);\n }\n \n if (filter?.isAnswered !== undefined) {\n params.push(`isAnswered=${filter.isAnswered}`);\n }\n \n if (filter?.page !== undefined) {\n params.push(`page=${filter.page}`);\n }\n \n if (filter?.pageSize !== undefined) {\n params.push(`pageSize=${filter.pageSize}`);\n }\n \n return params;\n };\n\n return {\n search: (query: string, page?: number) => {\n const body: { query: string; page?: number } = { query };\n if (page !== undefined) {\n body.page = page;\n }\n return requestAPI<any>('search', 'POST', body);\n },\n getQuestions: (filter?: QuestionsFilter) => {\n const params = buildQuestionParams(filter);\n return requestAPI<ApiResponse<Question>>('questions', 'GET', undefined, params.length > 0 ? params : undefined);\n },\n getTags: (search?: string) => {\n const params = search ? [`search=${encodeURIComponent(search)}`] : undefined;\n return requestAPI<ApiResponse<Tag>>('tags', 'GET', undefined, params);\n },\n getUsers: () => requestAPI<ApiResponse<User>>('users'),\n getMe: () => requestAPI<User>('me'),\n getBaseUrl: async () => {\n const response = await requestAPI<BaseUrlResponse>('baseurl');\n return response.SOInstance;\n },\n getTeamName: async () => {\n const response = await requestAPI<BaseUrlResponse>('baseurl')\n return response.teamName\n },\n postQuestion: (title: string, body: string, tags: string[]) =>\n requestAPI<Question>('questions', 'POST', { title, body, tags }),\n startAuth: async () => {\n const data = await requestAPI<{ authUrl: string }>('auth/start');\n return data.authUrl;\n },\n completeAuth: async (code: string, state: string) => {\n await requestAPI('callback', 'GET', undefined, [\n `code=${encodeURIComponent(code)}`,\n `state=${encodeURIComponent(state)}`,\n ]);\n },\n getAuthStatus: async (): Promise<boolean> => {\n try {\n await requestAPI('authStatus');\n return true;\n } catch {\n return false;\n }\n },\n logout: async (): Promise<boolean> => {\n try {\n await requestAPI('logout', 'POST');\n return true;\n } catch {\n return false;\n }\n },\n submitAccessToken: async (token: string): Promise<boolean> => {\n try {\n await requestAPI('auth/token', 'POST', { accessToken: token });\n return true;\n } catch {\n return false;\n }\n },\n\n // Convenience methods for common filtering scenarios\n getActiveQuestions: (page?: number) => {\n const params = buildQuestionParams({ sort: 'activity', order: 'desc', page });\n return requestAPI<ApiResponse<Question>>('questions', 'GET', undefined, params);\n },\n\n getNewestQuestions: (page?: number) => {\n const params = buildQuestionParams({ sort: 'creation', order: 'desc', page });\n return requestAPI<ApiResponse<Question>>('questions', 'GET', undefined, params);\n },\n\n getTopScoredQuestions: (page?: number) => {\n const params = buildQuestionParams({ sort: 'score', order: 'desc', page });\n return requestAPI<ApiResponse<Question>>('questions', 'GET', undefined, params);\n },\n\n getUnansweredQuestions: (page?: number) => {\n const params = buildQuestionParams({ isAnswered: false, sort: 'creation', order: 'desc', page });\n return requestAPI<ApiResponse<Question>>('questions', 'GET', undefined, params);\n },\n };\n};"],"names":[],"mappings":";;AAOO,MAAM,2BAA2B,YAAA,CAA+B;AAAA,EACrE,EAAA,EAAI;AACN,CAAC;AAwCM,MAAM,sBAAA,GAAyB,CACpC,YAAA,EACA,QAAA,KACqB;AACrB,EAAA,MAAM,UAAA,GAAa,YAAY,YAAA,CAAa,UAAA,CAAW,sBAAsB,CAAA;AAE7E,EAAA,MAAM,aAAa,OACjB,QAAA,EACA,MAAA,GAAyB,KAAA,EACzB,MACA,MAAA,KACe;AACf,IAAA,MAAM,OAAA,GAAU,MAAM,UAAA,EAAW;AACjC,IAAA,MAAM,cAAc,MAAA,GAAS,CAAA,CAAA,EAAI,OAAO,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA,GAAK,EAAA;AACtD,IAAA,MAAM,MAAM,CAAA,EAAG,OAAO,CAAA,CAAA,EAAI,QAAQ,GAAG,WAAW,CAAA,CAAA;AAEhD,IAAA,MAAM,QAAA,GAAW,MAAM,QAAA,CAAS,KAAA,CAAM,GAAA,EAAK;AAAA,MACzC,MAAA;AAAA,MACA,WAAA,EAAa,SAAA;AAAA,MACb,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAmB;AAAA,MAC9C,IAAA,EAAM,IAAA,GAAO,IAAA,CAAK,SAAA,CAAU,IAAI,CAAA,GAAI;AAAA,KACrC,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,aAAA,GAAgB,MAAM,QAAA,CAAS,IAAA,EAAK;AAC1C,MAAA,MAAM,IAAI,KAAA,CAAM,aAAA,CAAc,SAAS,CAAA,gBAAA,EAAmB,QAAA,CAAS,UAAU,CAAA,CAAE,CAAA;AAAA,IACjF;AAEA,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB,CAAA;AAEA,EAAA,MAAM,mBAAA,GAAsB,CAAC,MAAA,KAAuC;AAClE,IAAA,MAAM,SAAmB,EAAC;AAE1B,IAAA,IAAI,QAAQ,IAAA,EAAM;AAChB,MAAA,MAAA,CAAO,IAAA,CAAK,CAAA,KAAA,EAAQ,MAAA,CAAO,IAAI,CAAA,CAAE,CAAA;AAAA,IACnC;AAEA,IAAA,IAAI,QAAQ,KAAA,EAAO;AACjB,MAAA,MAAA,CAAO,IAAA,CAAK,CAAA,MAAA,EAAS,MAAA,CAAO,KAAK,CAAA,CAAE,CAAA;AAAA,IACrC;AAEA,IAAA,IAAI,MAAA,EAAQ,eAAe,MAAA,EAAW;AACpC,MAAA,MAAA,CAAO,IAAA,CAAK,CAAA,WAAA,EAAc,MAAA,CAAO,UAAU,CAAA,CAAE,CAAA;AAAA,IAC/C;AAEA,IAAA,IAAI,MAAA,EAAQ,SAAS,MAAA,EAAW;AAC9B,MAAA,MAAA,CAAO,IAAA,CAAK,CAAA,KAAA,EAAQ,MAAA,CAAO,IAAI,CAAA,CAAE,CAAA;AAAA,IACnC;AAEA,IAAA,IAAI,MAAA,EAAQ,aAAa,MAAA,EAAW;AAClC,MAAA,MAAA,CAAO,IAAA,CAAK,CAAA,SAAA,EAAY,MAAA,CAAO,QAAQ,CAAA,CAAE,CAAA;AAAA,IAC3C;AAEA,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,CAAC,KAAA,EAAe,IAAA,KAAkB;AACxC,MAAA,MAAM,IAAA,GAAyC,EAAE,KAAA,EAAM;AACvD,MAAA,IAAI,SAAS,MAAA,EAAW;AACtB,QAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AAAA,MACd;AACA,MAAA,OAAO,UAAA,CAAgB,QAAA,EAAU,MAAA,EAAQ,IAAI,CAAA;AAAA,IAC/C,CAAA;AAAA,IACA,YAAA,EAAc,CAAC,MAAA,KAA6B;AAC1C,MAAA,MAAM,MAAA,GAAS,oBAAoB,MAAM,CAAA;AACzC,MAAA,OAAO,UAAA,CAAkC,aAAa,KAAA,EAAO,MAAA,EAAW,OAAO,MAAA,GAAS,CAAA,GAAI,SAAS,MAAS,CAAA;AAAA,IAChH,CAAA;AAAA,IACA,OAAA,EAAS,CAAC,MAAA,KAAoB;AAC5B,MAAA,MAAM,MAAA,GAAS,SAAS,CAAC,CAAA,OAAA,EAAU,mBAAmB,MAAM,CAAC,EAAE,CAAA,GAAI,MAAA;AACnE,MAAA,OAAO,UAAA,CAA6B,MAAA,EAAQ,KAAA,EAAO,MAAA,EAAW,MAAM,CAAA;AAAA,IACtE,CAAA;AAAA,IACA,QAAA,EAAU,MAAM,UAAA,CAA8B,OAAO,CAAA;AAAA,IACrD,KAAA,EAAO,MAAM,UAAA,CAAiB,IAAI,CAAA;AAAA,IAClC,YAAY,YAAY;AACtB,MAAA,MAAM,QAAA,GAAW,MAAM,UAAA,CAA4B,SAAS,CAAA;AAC5D,MAAA,OAAO,QAAA,CAAS,UAAA;AAAA,IAClB,CAAA;AAAA,IACA,aAAa,YAAY;AACvB,MAAA,MAAM,QAAA,GAAW,MAAM,UAAA,CAA4B,SAAS,CAAA;AAC5D,MAAA,OAAO,QAAA,CAAS,QAAA;AAAA,IAClB,CAAA;AAAA,IACA,YAAA,EAAc,CAAC,KAAA,EAAe,IAAA,EAAc,IAAA,KAC1C,UAAA,CAAqB,WAAA,EAAa,MAAA,EAAQ,EAAE,KAAA,EAAO,IAAA,EAAM,IAAA,EAAM,CAAA;AAAA,IACjE,WAAW,YAAY;AACrB,MAAA,MAAM,IAAA,GAAO,MAAM,UAAA,CAAgC,YAAY,CAAA;AAC/D,MAAA,OAAO,IAAA,CAAK,OAAA;AAAA,IACd,CAAA;AAAA,IACA,YAAA,EAAc,OAAO,IAAA,EAAc,KAAA,KAAkB;AACnD,MAAA,MAAM,UAAA,CAAW,UAAA,EAAY,KAAA,EAAO,MAAA,EAAW;AAAA,QAC7C,CAAA,KAAA,EAAQ,kBAAA,CAAmB,IAAI,CAAC,CAAA,CAAA;AAAA,QAChC,CAAA,MAAA,EAAS,kBAAA,CAAmB,KAAK,CAAC,CAAA;AAAA,OACnC,CAAA;AAAA,IACH,CAAA;AAAA,IACA,eAAe,YAA8B;AAC3C,MAAA,IAAI;AACF,QAAA,MAAM,WAAW,YAAY,CAAA;AAC7B,QAAA,OAAO,IAAA;AAAA,MACT,CAAA,CAAA,MAAQ;AACN,QAAA,OAAO,KAAA;AAAA,MACT;AAAA,IACF,CAAA;AAAA,IACA,QAAQ,YAA8B;AACpC,MAAA,IAAI;AACF,QAAA,MAAM,UAAA,CAAW,UAAU,MAAM,CAAA;AACjC,QAAA,OAAO,IAAA;AAAA,MACT,CAAA,CAAA,MAAQ;AACN,QAAA,OAAO,KAAA;AAAA,MACT;AAAA,IACF,CAAA;AAAA,IACA,iBAAA,EAAmB,OAAO,KAAA,KAAoC;AAC5D,MAAA,IAAI;AACF,QAAA,MAAM,WAAW,YAAA,EAAc,MAAA,EAAQ,EAAE,WAAA,EAAa,OAAO,CAAA;AAC7D,QAAA,OAAO,IAAA;AAAA,MACT,CAAA,CAAA,MAAQ;AACN,QAAA,OAAO,KAAA;AAAA,MACT;AAAA,IACF,CAAA;AAAA;AAAA,IAGA,kBAAA,EAAoB,CAAC,IAAA,KAAkB;AACrC,MAAA,MAAM,MAAA,GAAS,oBAAoB,EAAE,IAAA,EAAM,YAAY,KAAA,EAAO,MAAA,EAAQ,MAAM,CAAA;AAC5E,MAAA,OAAO,UAAA,CAAkC,WAAA,EAAa,KAAA,EAAO,MAAA,EAAW,MAAM,CAAA;AAAA,IAChF,CAAA;AAAA,IAEA,kBAAA,EAAoB,CAAC,IAAA,KAAkB;AACrC,MAAA,MAAM,MAAA,GAAS,oBAAoB,EAAE,IAAA,EAAM,YAAY,KAAA,EAAO,MAAA,EAAQ,MAAM,CAAA;AAC5E,MAAA,OAAO,UAAA,CAAkC,WAAA,EAAa,KAAA,EAAO,MAAA,EAAW,MAAM,CAAA;AAAA,IAChF,CAAA;AAAA,IAEA,qBAAA,EAAuB,CAAC,IAAA,KAAkB;AACxC,MAAA,MAAM,MAAA,GAAS,oBAAoB,EAAE,IAAA,EAAM,SAAS,KAAA,EAAO,MAAA,EAAQ,MAAM,CAAA;AACzE,MAAA,OAAO,UAAA,CAAkC,WAAA,EAAa,KAAA,EAAO,MAAA,EAAW,MAAM,CAAA;AAAA,IAChF,CAAA;AAAA,IAEA,sBAAA,EAAwB,CAAC,IAAA,KAAkB;AACzC,MAAA,MAAM,MAAA,GAAS,mBAAA,CAAoB,EAAE,UAAA,EAAY,KAAA,EAAO,MAAM,UAAA,EAAY,KAAA,EAAO,MAAA,EAAQ,IAAA,EAAM,CAAA;AAC/F,MAAA,OAAO,UAAA,CAAkC,WAAA,EAAa,KAAA,EAAO,MAAA,EAAW,MAAM,CAAA;AAAA,IAChF;AAAA,GACF;AACF;;;;"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import { useApi } from '@backstage/core-plugin-api';
|
|
3
|
+
import { stackoverflowteamsApiRef } from '../../api/StackOverflowAPI.esm.js';
|
|
4
|
+
import { useState, useEffect } from 'react';
|
|
5
|
+
import { Box, CircularProgress, Typography, Card, IconButton, CardContent, Avatar, Chip, Link } from '@mui/material';
|
|
6
|
+
import { LogoutIcon } from '../../icons/LogoutIcon.esm.js';
|
|
7
|
+
|
|
8
|
+
const StackOverflowMe = () => {
|
|
9
|
+
const stackOverflowTeamsApi = useApi(stackoverflowteamsApiRef);
|
|
10
|
+
const logout = async () => {
|
|
11
|
+
try {
|
|
12
|
+
const success = await stackOverflowTeamsApi.logout();
|
|
13
|
+
if (success) {
|
|
14
|
+
window.location.reload();
|
|
15
|
+
} else {
|
|
16
|
+
throw new Error("Logout failed.");
|
|
17
|
+
}
|
|
18
|
+
} catch (error2) {
|
|
19
|
+
throw new Error("Error during logout:", error2);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
const [userData, setUserData] = useState(null);
|
|
23
|
+
const [loading, setLoading] = useState(true);
|
|
24
|
+
const [error, setError] = useState(null);
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
const fetchMe = async () => {
|
|
27
|
+
try {
|
|
28
|
+
const data = await stackOverflowTeamsApi.getMe();
|
|
29
|
+
setUserData(data);
|
|
30
|
+
} catch (err) {
|
|
31
|
+
setError("Failed to load user data");
|
|
32
|
+
} finally {
|
|
33
|
+
setLoading(false);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
fetchMe();
|
|
37
|
+
}, [stackOverflowTeamsApi]);
|
|
38
|
+
if (loading) {
|
|
39
|
+
return /* @__PURE__ */ jsx(
|
|
40
|
+
Box,
|
|
41
|
+
{
|
|
42
|
+
display: "flex",
|
|
43
|
+
justifyContent: "center",
|
|
44
|
+
alignItems: "center",
|
|
45
|
+
width: "100%",
|
|
46
|
+
children: /* @__PURE__ */ jsx(CircularProgress, { color: "primary" })
|
|
47
|
+
}
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
if (error) {
|
|
51
|
+
return /* @__PURE__ */ jsx(
|
|
52
|
+
Box,
|
|
53
|
+
{
|
|
54
|
+
display: "flex",
|
|
55
|
+
justifyContent: "center",
|
|
56
|
+
alignItems: "center",
|
|
57
|
+
width: "100%",
|
|
58
|
+
children: /* @__PURE__ */ jsx(Typography, { color: "error", children: error })
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
if (!userData) return null;
|
|
63
|
+
return /* @__PURE__ */ jsx(
|
|
64
|
+
Box,
|
|
65
|
+
{
|
|
66
|
+
display: "flex",
|
|
67
|
+
justifyContent: "center",
|
|
68
|
+
alignItems: "center",
|
|
69
|
+
width: "100%",
|
|
70
|
+
children: /* @__PURE__ */ jsxs(
|
|
71
|
+
Card,
|
|
72
|
+
{
|
|
73
|
+
variant: "outlined",
|
|
74
|
+
sx: {
|
|
75
|
+
p: 3,
|
|
76
|
+
position: "relative",
|
|
77
|
+
boxShadow: 3
|
|
78
|
+
},
|
|
79
|
+
children: [
|
|
80
|
+
/* @__PURE__ */ jsx(Box, { sx: { position: "absolute", top: 8, right: 8 }, children: /* @__PURE__ */ jsx(
|
|
81
|
+
IconButton,
|
|
82
|
+
{
|
|
83
|
+
onClick: logout,
|
|
84
|
+
children: /* @__PURE__ */ jsx(LogoutIcon, {})
|
|
85
|
+
}
|
|
86
|
+
) }),
|
|
87
|
+
/* @__PURE__ */ jsxs(CardContent, { sx: { textAlign: "center" }, children: [
|
|
88
|
+
/* @__PURE__ */ jsx(Avatar, { src: userData.avatarUrl, sx: { mx: "auto", mb: 2 } }),
|
|
89
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h6", fontWeight: "bold", gutterBottom: true, children: userData.name }),
|
|
90
|
+
/* @__PURE__ */ jsxs(Box, { display: "flex", justifyContent: "center", gap: 1, mb: 1, children: [
|
|
91
|
+
/* @__PURE__ */ jsx(
|
|
92
|
+
Chip,
|
|
93
|
+
{
|
|
94
|
+
label: `Reputation: ${userData.reputation}`,
|
|
95
|
+
size: "small",
|
|
96
|
+
color: "primary"
|
|
97
|
+
}
|
|
98
|
+
),
|
|
99
|
+
/* @__PURE__ */ jsx(Chip, { label: userData.role, size: "small", variant: "outlined" })
|
|
100
|
+
] }),
|
|
101
|
+
userData.jobTitle && /* @__PURE__ */ jsxs(Typography, { variant: "body2", fontWeight: "500", mt: 1, children: [
|
|
102
|
+
"Position: ",
|
|
103
|
+
userData.jobTitle
|
|
104
|
+
] }),
|
|
105
|
+
/* @__PURE__ */ jsx(
|
|
106
|
+
Link,
|
|
107
|
+
{
|
|
108
|
+
href: userData.webUrl,
|
|
109
|
+
target: "_blank",
|
|
110
|
+
rel: "noopener",
|
|
111
|
+
color: "primary",
|
|
112
|
+
sx: { display: "block", mt: 2, fontWeight: "bold" },
|
|
113
|
+
children: "View Profile"
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
] })
|
|
117
|
+
]
|
|
118
|
+
}
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export { StackOverflowMe };
|
|
125
|
+
//# sourceMappingURL=StackOverflowMe.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StackOverflowMe.esm.js","sources":["../../../src/components/StackOverflow/StackOverflowMe.tsx"],"sourcesContent":["import { useApi } from '@backstage/core-plugin-api';\nimport { stackoverflowteamsApiRef, User } from '../../api';\nimport { useEffect, useState } from 'react';\n// eslint-disable-next-line no-restricted-imports\nimport {\n Box,\n Avatar,\n Typography,\n Card,\n CardContent,\n Link,\n CircularProgress,\n Chip,\n IconButton,\n} from '@mui/material';\nimport { LogoutIcon } from '../../icons';\n\nexport const StackOverflowMe = () => {\n const stackOverflowTeamsApi = useApi(stackoverflowteamsApiRef);\n const logout = async () => {\n try {\n const success = await stackOverflowTeamsApi.logout();\n if (success) {\n window.location.reload();\n } else {\n throw new Error('Logout failed.');\n }\n } catch (error:any) {\n throw new Error('Error during logout:', error);\n }\n };\n\n const [userData, setUserData] = useState<User | null>(null);\n const [loading, setLoading] = useState<Boolean>(true);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n const fetchMe = async () => {\n try {\n const data = await stackOverflowTeamsApi.getMe();\n setUserData(data);\n } catch (err) {\n setError('Failed to load user data');\n } finally {\n setLoading(false);\n }\n };\n\n fetchMe();\n }, [stackOverflowTeamsApi]);\n\n if (loading) {\n return (\n <Box\n display=\"flex\"\n justifyContent=\"center\"\n alignItems=\"center\"\n width=\"100%\"\n >\n <CircularProgress color=\"primary\" />\n </Box>\n );\n }\n\n if (error) {\n return (\n <Box\n display=\"flex\"\n justifyContent=\"center\"\n alignItems=\"center\"\n width=\"100%\"\n >\n <Typography color=\"error\">{error}</Typography>\n </Box>\n );\n }\n\n if (!userData) return null;\n\n return (\n <Box\n display=\"flex\"\n justifyContent=\"center\"\n alignItems=\"center\"\n width=\"100%\"\n >\n <Card\n variant=\"outlined\"\n sx={{\n p: 3,\n position: 'relative',\n boxShadow: 3,\n }}\n >\n {/* Logout Button */}\n <Box sx={{ position: 'absolute', top: 8, right: 8 }}>\n <IconButton\n \n onClick={logout}\n >\n <LogoutIcon />\n </IconButton>\n </Box>\n <CardContent sx={{ textAlign: 'center' }}>\n {/* Avatar */}\n <Avatar src={userData.avatarUrl} sx={{ mx: 'auto', mb: 2 }} />\n\n {/* User Details */}\n <Typography variant=\"h6\" fontWeight=\"bold\" gutterBottom>\n {userData.name}\n </Typography>\n\n <Box display=\"flex\" justifyContent=\"center\" gap={1} mb={1}>\n <Chip\n label={`Reputation: ${userData.reputation}`}\n size=\"small\"\n color=\"primary\"\n />\n <Chip label={userData.role} size=\"small\" variant=\"outlined\" />\n </Box>\n\n {userData.jobTitle && (\n <Typography variant=\"body2\" fontWeight=\"500\" mt={1}>\n Position: {userData.jobTitle}\n </Typography>\n )}\n\n {/* Profile Link */}\n <Link\n href={userData.webUrl}\n target=\"_blank\"\n rel=\"noopener\"\n color=\"primary\"\n sx={{ display: 'block', mt: 2, fontWeight: 'bold' }}\n >\n View Profile\n </Link>\n </CardContent>\n </Card>\n </Box>\n );\n};\n"],"names":["error"],"mappings":";;;;;;;AAiBO,MAAM,kBAAkB,MAAM;AACnC,EAAA,MAAM,qBAAA,GAAwB,OAAO,wBAAwB,CAAA;AAC7D,EAAA,MAAM,SAAS,YAAY;AACzB,IAAA,IAAI;AACF,MAAA,MAAM,OAAA,GAAU,MAAM,qBAAA,CAAsB,MAAA,EAAO;AACnD,MAAA,IAAI,OAAA,EAAS;AACX,QAAA,MAAA,CAAO,SAAS,MAAA,EAAO;AAAA,MACzB,CAAA,MAAO;AACL,QAAA,MAAM,IAAI,MAAM,gBAAgB,CAAA;AAAA,MAClC;AAAA,IACF,SAASA,MAAAA,EAAW;AAClB,MAAA,MAAM,IAAI,KAAA,CAAM,sBAAA,EAAwBA,MAAK,CAAA;AAAA,IAC/C;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAI,SAAsB,IAAI,CAAA;AAC1D,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAkB,IAAI,CAAA;AACpD,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAwB,IAAI,CAAA;AAEtD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,UAAU,YAAY;AAC1B,MAAA,IAAI;AACF,QAAA,MAAM,IAAA,GAAO,MAAM,qBAAA,CAAsB,KAAA,EAAM;AAC/C,QAAA,WAAA,CAAY,IAAI,CAAA;AAAA,MAClB,SAAS,GAAA,EAAK;AACZ,QAAA,QAAA,CAAS,0BAA0B,CAAA;AAAA,MACrC,CAAA,SAAE;AACA,QAAA,UAAA,CAAW,KAAK,CAAA;AAAA,MAClB;AAAA,IACF,CAAA;AAEA,IAAA,OAAA,EAAQ;AAAA,EACV,CAAA,EAAG,CAAC,qBAAqB,CAAC,CAAA;AAE1B,EAAA,IAAI,OAAA,EAAS;AACX,IAAA,uBACE,GAAA;AAAA,MAAC,GAAA;AAAA,MAAA;AAAA,QACC,OAAA,EAAQ,MAAA;AAAA,QACR,cAAA,EAAe,QAAA;AAAA,QACf,UAAA,EAAW,QAAA;AAAA,QACX,KAAA,EAAM,MAAA;AAAA,QAEN,QAAA,kBAAA,GAAA,CAAC,gBAAA,EAAA,EAAiB,KAAA,EAAM,SAAA,EAAU;AAAA;AAAA,KACpC;AAAA,EAEJ;AAEA,EAAA,IAAI,KAAA,EAAO;AACT,IAAA,uBACE,GAAA;AAAA,MAAC,GAAA;AAAA,MAAA;AAAA,QACC,OAAA,EAAQ,MAAA;AAAA,QACR,cAAA,EAAe,QAAA;AAAA,QACf,UAAA,EAAW,QAAA;AAAA,QACX,KAAA,EAAM,MAAA;AAAA,QAEN,QAAA,kBAAA,GAAA,CAAC,UAAA,EAAA,EAAW,KAAA,EAAM,OAAA,EAAS,QAAA,EAAA,KAAA,EAAM;AAAA;AAAA,KACnC;AAAA,EAEJ;AAEA,EAAA,IAAI,CAAC,UAAU,OAAO,IAAA;AAEtB,EAAA,uBACE,GAAA;AAAA,IAAC,GAAA;AAAA,IAAA;AAAA,MACC,OAAA,EAAQ,MAAA;AAAA,MACR,cAAA,EAAe,QAAA;AAAA,MACf,UAAA,EAAW,QAAA;AAAA,MACX,KAAA,EAAM,MAAA;AAAA,MAEN,QAAA,kBAAA,IAAA;AAAA,QAAC,IAAA;AAAA,QAAA;AAAA,UACC,OAAA,EAAQ,UAAA;AAAA,UACR,EAAA,EAAI;AAAA,YACF,CAAA,EAAG,CAAA;AAAA,YACH,QAAA,EAAU,UAAA;AAAA,YACV,SAAA,EAAW;AAAA,WACb;AAAA,UAGA,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,GAAA,EAAA,EAAI,IAAI,EAAE,QAAA,EAAU,YAAY,GAAA,EAAK,CAAA,EAAG,KAAA,EAAO,CAAA,EAAE,EAClD,QAAA,kBAAA,GAAA;AAAA,cAAC,UAAA;AAAA,cAAA;AAAA,gBAEC,OAAA,EAAS,MAAA;AAAA,gBAET,8BAAC,UAAA,EAAA,EAAW;AAAA;AAAA,aACd,EACA,CAAA;AAAA,iCACC,WAAA,EAAA,EAAY,EAAA,EAAI,EAAE,SAAA,EAAW,UAAS,EAErC,QAAA,EAAA;AAAA,8BAAA,GAAA,CAAC,MAAA,EAAA,EAAO,GAAA,EAAK,QAAA,CAAS,SAAA,EAAW,EAAA,EAAI,EAAE,EAAA,EAAI,MAAA,EAAQ,EAAA,EAAI,CAAA,EAAE,EAAG,CAAA;AAAA,8BAG5D,GAAA,CAAC,cAAW,OAAA,EAAQ,IAAA,EAAK,YAAW,MAAA,EAAO,YAAA,EAAY,IAAA,EACpD,QAAA,EAAA,QAAA,CAAS,IAAA,EACZ,CAAA;AAAA,8BAEA,IAAA,CAAC,OAAI,OAAA,EAAQ,MAAA,EAAO,gBAAe,QAAA,EAAS,GAAA,EAAK,CAAA,EAAG,EAAA,EAAI,CAAA,EACtD,QAAA,EAAA;AAAA,gCAAA,GAAA;AAAA,kBAAC,IAAA;AAAA,kBAAA;AAAA,oBACC,KAAA,EAAO,CAAA,YAAA,EAAe,QAAA,CAAS,UAAU,CAAA,CAAA;AAAA,oBACzC,IAAA,EAAK,OAAA;AAAA,oBACL,KAAA,EAAM;AAAA;AAAA,iBACR;AAAA,gCACA,GAAA,CAAC,QAAK,KAAA,EAAO,QAAA,CAAS,MAAM,IAAA,EAAK,OAAA,EAAQ,SAAQ,UAAA,EAAW;AAAA,eAAA,EAC9D,CAAA;AAAA,cAEC,QAAA,CAAS,4BACR,IAAA,CAAC,UAAA,EAAA,EAAW,SAAQ,OAAA,EAAQ,UAAA,EAAW,KAAA,EAAM,EAAA,EAAI,CAAA,EAAG,QAAA,EAAA;AAAA,gBAAA,YAAA;AAAA,gBACvC,QAAA,CAAS;AAAA,eAAA,EACtB,CAAA;AAAA,8BAIF,GAAA;AAAA,gBAAC,IAAA;AAAA,gBAAA;AAAA,kBACC,MAAM,QAAA,CAAS,MAAA;AAAA,kBACf,MAAA,EAAO,QAAA;AAAA,kBACP,GAAA,EAAI,UAAA;AAAA,kBACJ,KAAA,EAAM,SAAA;AAAA,kBACN,IAAI,EAAE,OAAA,EAAS,SAAS,EAAA,EAAI,CAAA,EAAG,YAAY,MAAA,EAAO;AAAA,kBACnD,QAAA,EAAA;AAAA;AAAA;AAED,aAAA,EACF;AAAA;AAAA;AAAA;AACF;AAAA,GACF;AAEJ;;;;"}
|